Import dotnetDBF for error handling.
This commit is contained in:
@@ -5,6 +5,10 @@ VisualStudioVersion = 16.0.29613.14
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImEXOnlinePartner", "BodyshopUploader\ImEXOnlinePartner.csproj", "{76B98E9B-A33A-464F-A07B-56E773376543}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetDBF", "dotnetdbf\DotNetDBF.csproj", "{9508821B-3B85-4088-8076-D0F0AF00DB55}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetDBF.Enumerable", "DotNetDBF.Enumerable\DotNetDBF.Enumerable.csproj", "{83E3893B-E266-475F-BAA4-0BFA8393CDCF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -27,6 +31,30 @@ Global
|
||||
{76B98E9B-A33A-464F-A07B-56E773376543}.Test|Any CPU.Build.0 = Test|Any CPU
|
||||
{76B98E9B-A33A-464F-A07B-56E773376543}.Test|x86.ActiveCfg = Test|x86
|
||||
{76B98E9B-A33A-464F-A07B-56E773376543}.Test|x86.Build.0 = Test|x86
|
||||
{9508821B-3B85-4088-8076-D0F0AF00DB55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9508821B-3B85-4088-8076-D0F0AF00DB55}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9508821B-3B85-4088-8076-D0F0AF00DB55}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9508821B-3B85-4088-8076-D0F0AF00DB55}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9508821B-3B85-4088-8076-D0F0AF00DB55}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9508821B-3B85-4088-8076-D0F0AF00DB55}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9508821B-3B85-4088-8076-D0F0AF00DB55}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9508821B-3B85-4088-8076-D0F0AF00DB55}.Release|x86.Build.0 = Release|Any CPU
|
||||
{9508821B-3B85-4088-8076-D0F0AF00DB55}.Test|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9508821B-3B85-4088-8076-D0F0AF00DB55}.Test|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9508821B-3B85-4088-8076-D0F0AF00DB55}.Test|x86.ActiveCfg = Debug|Any CPU
|
||||
{9508821B-3B85-4088-8076-D0F0AF00DB55}.Test|x86.Build.0 = Debug|Any CPU
|
||||
{83E3893B-E266-475F-BAA4-0BFA8393CDCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{83E3893B-E266-475F-BAA4-0BFA8393CDCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{83E3893B-E266-475F-BAA4-0BFA8393CDCF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{83E3893B-E266-475F-BAA4-0BFA8393CDCF}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{83E3893B-E266-475F-BAA4-0BFA8393CDCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{83E3893B-E266-475F-BAA4-0BFA8393CDCF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{83E3893B-E266-475F-BAA4-0BFA8393CDCF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{83E3893B-E266-475F-BAA4-0BFA8393CDCF}.Release|x86.Build.0 = Release|Any CPU
|
||||
{83E3893B-E266-475F-BAA4-0BFA8393CDCF}.Test|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{83E3893B-E266-475F-BAA4-0BFA8393CDCF}.Test|Any CPU.Build.0 = Debug|Any CPU
|
||||
{83E3893B-E266-475F-BAA4-0BFA8393CDCF}.Test|x86.ActiveCfg = Debug|Any CPU
|
||||
{83E3893B-E266-475F-BAA4-0BFA8393CDCF}.Test|x86.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -348,9 +348,6 @@
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNetDBF">
|
||||
<Version>6.0.0.3</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FileHelpers">
|
||||
<Version>3.5.1</Version>
|
||||
</PackageReference>
|
||||
@@ -537,6 +534,16 @@
|
||||
<Version>2.5.1</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DotNetDBF.Enumerable\DotNetDBF.Enumerable.csproj">
|
||||
<Project>{83e3893b-e266-475f-baa4-0bfa8393cdcf}</Project>
|
||||
<Name>DotNetDBF.Enumerable</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\dotnetdbf\DotNetDBF.csproj">
|
||||
<Project>{9508821b-3b85-4088-8076-d0f0af00db55}</Project>
|
||||
<Name>DotNetDBF</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="AfterBuild" Condition=" '$(Configuration)' == 'Release'">
|
||||
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
|
||||
|
||||
@@ -56,4 +56,6 @@ CA63387A44437B55CD283AB4A2CB92385F1321E7 ImEXOnlinePartner-1.0.28-full.nupkg 550
|
||||
36869986F57C7F0E25610A10F43C740DAC7639A2 ImEXOnlinePartner-1.0.29-delta.nupkg 56217
|
||||
6F104EF819C1791FD334CE21CEE9C6B8DB3FC105 ImEXOnlinePartner-1.0.29-full.nupkg 5510931
|
||||
D441404BE86E0A676462DD367D4355894C2FFDBA ImEXOnlinePartner-1.0.30-delta.nupkg 62664
|
||||
66963D1624BD0C662CDF6E93B87D9AE4FA8073FF ImEXOnlinePartner-1.0.30-full.nupkg 5512346
|
||||
66963D1624BD0C662CDF6E93B87D9AE4FA8073FF ImEXOnlinePartner-1.0.30-full.nupkg 5512346
|
||||
8F1739F9B7C202F7E2453E7D5027F7422637D206 ImEXOnlinePartner-1.0.31-delta.nupkg 152092
|
||||
6B3D3A0DD81D6F0C302ACE42DEDDDFC11270DD22 ImEXOnlinePartner-1.0.31-full.nupkg 5609086
|
||||
@@ -1077,8 +1077,8 @@ namespace BodyshopPartner.Utils.Decoder
|
||||
|
||||
for (int i = 0; i < reader.RecordCount; i++)
|
||||
{
|
||||
|
||||
var readValues = reader.NextRecord();
|
||||
logger.Debug($"Reading line {i +1}");
|
||||
var readValues = reader.NextRecord(false);
|
||||
dynamic lin = new JObject();
|
||||
|
||||
//Mising est_seq
|
||||
@@ -1165,7 +1165,12 @@ namespace BodyshopPartner.Utils.Decoder
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.Trace(ex, "Unable to open LIN file. Retrying. ");
|
||||
logger.Error(ex, "Unable to open LIN file. Retrying. ");
|
||||
retryNumber++;
|
||||
Thread.Sleep(retrySleep);
|
||||
}catch(Exception Ex)
|
||||
{
|
||||
logger.Error(Ex, "Unable to open LIN file. Retrying. Unknown Exception ");
|
||||
retryNumber++;
|
||||
Thread.Sleep(retrySleep);
|
||||
}
|
||||
|
||||
504
Copying.TXT
Normal file
504
Copying.TXT
Normal file
@@ -0,0 +1,504 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
38
DotNetDBF.Enumerable/DotNetDBF.Enumerable.csproj
Normal file
38
DotNetDBF.Enumerable/DotNetDBF.Enumerable.csproj
Normal file
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net40;netstandard2.0</TargetFrameworks>
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>sn.snk</AssemblyOriginatorKeyFile>
|
||||
<PackageId>dotnetdbf.enumerable</PackageId>
|
||||
<Authors>Jay Tuley</Authors>
|
||||
<Company>Ekon Benefits</Company>
|
||||
<Description>For dotnetdbf projects using .net 4.0 projects this is an enumeration framework in which makes it easy to use Linq to Objects.</Description>
|
||||
<PackageLicense>lgpl</PackageLicense>
|
||||
<PackageProjectUrl>https://github.com/ekonbenefits/dotnetdbf</PackageProjectUrl>
|
||||
<PackageTags>clipper xbase dbf linq</PackageTags>
|
||||
<PackageLicenseExpression>LGPL-2.1-or-later</PackageLicenseExpression>
|
||||
<PackageIconUrl>https://github.com/ekonbenefits/dotnetdbf</PackageIconUrl>
|
||||
<RepositoryUrl>https://github.com/ekonbenefits/dotnetdbf.git</RepositoryUrl>
|
||||
<RepositoryType>gits</RepositoryType>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<Version>6.0.0.2</Version>
|
||||
<IncludeSymbols>True</IncludeSymbols>
|
||||
<IncludeSource>True</IncludeSource>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\Copying.txt" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-18618-05" PrivateAssets="All"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ImpromptuInterface" Version="7.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DotNetDBF\DotNetDBF.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
271
DotNetDBF.Enumerable/Enumerable.cs
Normal file
271
DotNetDBF.Enumerable/Enumerable.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ImpromptuInterface;
|
||||
using Dynamitey;
|
||||
|
||||
namespace DotNetDBF.Enumerable
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface to get the contents of the DBF Wrapper
|
||||
/// </summary>
|
||||
public interface IDBFInterceptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Does field exist in row
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool Exists(string fieldName);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data row.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
object[] GetDataRow();
|
||||
}
|
||||
|
||||
#pragma warning disable 618
|
||||
public class DBFInterceptor : DBFIntercepter
|
||||
#pragma warning restore 618
|
||||
{
|
||||
public DBFInterceptor(object[] wrappedObj, string[] fieldNames) : base(wrappedObj, fieldNames)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DBF Dynamic Wrapper
|
||||
/// </summary>
|
||||
public abstract class BaseDBFInterceptor : Dynamitey.DynamicObjects.BaseObject, IDBFInterceptor
|
||||
{
|
||||
private readonly string[] _fieldNames;
|
||||
private readonly object[] _wrappedArray;
|
||||
|
||||
protected BaseDBFInterceptor(object[] wrappedObj, string[] fieldNames)
|
||||
{
|
||||
_wrappedArray = wrappedObj;
|
||||
_fieldNames = fieldNames;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDynamicMemberNames()
|
||||
{
|
||||
return _fieldNames;
|
||||
}
|
||||
|
||||
public bool Exists(string fieldName)
|
||||
{
|
||||
return _fieldNames.Contains(fieldName);
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
result = null;
|
||||
var tLookup = binder.Name;
|
||||
var tIndex = Array.FindIndex(_fieldNames,
|
||||
it => it.Equals(tLookup, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
if (tIndex < 0)
|
||||
return false;
|
||||
|
||||
|
||||
result = _wrappedArray[tIndex];
|
||||
|
||||
|
||||
if (TryTypeForName(tLookup, out var outType))
|
||||
{
|
||||
result = Dynamic.CoerceConvert(result, outType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
var tLookup = binder.Name;
|
||||
var tIndex = Array.FindIndex(_fieldNames,
|
||||
it => it.Equals(tLookup, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
if (tIndex < 0)
|
||||
return false;
|
||||
|
||||
if (TryTypeForName(tLookup, out var outType))
|
||||
{
|
||||
value = Dynamic.CoerceConvert(value, outType);
|
||||
}
|
||||
|
||||
_wrappedArray[tIndex] = value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public object[] GetDataRow()
|
||||
{
|
||||
return _wrappedArray;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerable API
|
||||
/// </summary>
|
||||
public static partial class DBFEnumerable
|
||||
{
|
||||
/// <summary>
|
||||
/// New Blank Row Dynamic object that matches writer;
|
||||
/// </summary>
|
||||
/// <param name="writer">The writer.</param>
|
||||
/// <returns></returns>
|
||||
public static dynamic NewBlankRow(this DBFWriter writer)
|
||||
{
|
||||
var fields = writer.Fields.Select(it => it.Name).ToArray();
|
||||
var obj = new object[fields.Length];
|
||||
return new Enumerable.DBFInterceptor(obj, fields);
|
||||
}
|
||||
|
||||
public static void CopyRecordTo(this IDBFInterceptor original, IDBFInterceptor dest)
|
||||
{
|
||||
foreach (var fieldName in Dynamitey.Dynamic.GetMemberNames(dest, true))
|
||||
{
|
||||
try
|
||||
{
|
||||
var val = Dynamic.InvokeGet(original, fieldName);
|
||||
Dynamic.InvokeSet(dest, fieldName, val);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Writes the record.
|
||||
/// </summary>
|
||||
/// <param name="writer">The writer.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
public static void WriteRecord(this DBFWriter writer, Enumerable.IDBFInterceptor value)
|
||||
{
|
||||
writer.WriteRecord(value.GetDataRow());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the record.
|
||||
/// </summary>
|
||||
/// <param name="writer">The writer.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
public static void AddRecord(this DBFWriter writer, Enumerable.IDBFInterceptor value)
|
||||
{
|
||||
writer.AddRecord(value.GetDataRow());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return all the records. T should be interface with getter properties that match types and names of the database.
|
||||
/// Optionally instead of T being and interface you can pass in an anonymous object with properties that match that
|
||||
/// database and then you'll get an IEnumerable of that anonymous type with the data filled in.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="prototype">The prototype. Anonymous class instance</param>
|
||||
/// <param name="throwOnParsingError">Indicates if parsing error throws an exception. Default: true</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> AllRecords<T>(this DBFReader reader, T prototype = null, bool throwOnParsingError = true) where T : class
|
||||
{
|
||||
var tType = typeof(T);
|
||||
|
||||
var tProperties = tType.GetProperties()
|
||||
.Where(
|
||||
it =>
|
||||
Array.FindIndex(reader.Fields,
|
||||
f => f.Name.Equals(it.Name, StringComparison.InvariantCultureIgnoreCase)) >= 0)
|
||||
.ToList();
|
||||
var tProps = tProperties
|
||||
.Select(
|
||||
it =>
|
||||
Array.FindIndex(reader.Fields,
|
||||
jt => jt.Name.Equals(it.Name, StringComparison.InvariantCultureIgnoreCase)))
|
||||
.Where(it => it >= 0)
|
||||
.ToArray();
|
||||
|
||||
var tOrderedProps = tProps.OrderBy(it => it).ToArray();
|
||||
var tReturn = new List<T>();
|
||||
|
||||
|
||||
if (tType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any())
|
||||
{
|
||||
var tAnon = reader.NextRecord(tProps, tOrderedProps, throwOnParsingError);
|
||||
while (tAnon != null)
|
||||
{
|
||||
tReturn.Add((T) Activator.CreateInstance(tType, tAnon));
|
||||
tAnon = reader.NextRecord(tProps, tOrderedProps, throwOnParsingError);
|
||||
}
|
||||
|
||||
|
||||
return tReturn;
|
||||
}
|
||||
|
||||
var t = reader.NextRecord(tProps, tOrderedProps, throwOnParsingError);
|
||||
|
||||
while (t != null)
|
||||
{
|
||||
var interceptor = new Enumerable.DBFInterceptor(t, tProperties.Select(it => it.Name).ToArray());
|
||||
|
||||
tReturn.Add(interceptor.ActLike<T>(typeof(Enumerable.IDBFInterceptor)));
|
||||
t = reader.NextRecord(tProps, tOrderedProps, throwOnParsingError);
|
||||
}
|
||||
|
||||
|
||||
return tReturn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of dynamic objects whose properties and types match up with that database name.
|
||||
/// </summary>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="whereColumn">The where column name.</param>
|
||||
/// <param name="whereColumnEquals">What the were column should equal.</param>
|
||||
/// <param name="throwOnParsingError">Indicates if parsing error throws an exception. Default: true</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<dynamic> DynamicAllRecords(this DBFReader reader, string whereColumn = null,
|
||||
dynamic whereColumnEquals = null, bool throwOnParsingError = true)
|
||||
{
|
||||
var props = reader.GetSelectFields().Select(it => it.Name).ToArray();
|
||||
|
||||
int? whereColumnIndex = null;
|
||||
if (!String.IsNullOrEmpty(whereColumn))
|
||||
{
|
||||
whereColumnIndex = Array.FindIndex(props,
|
||||
it => it.Equals(whereColumn, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
|
||||
|
||||
var tReturn = new List<object>();
|
||||
var t = reader.NextRecord(throwOnParsingError);
|
||||
|
||||
while (t != null)
|
||||
{
|
||||
if (whereColumnIndex is int i)
|
||||
{
|
||||
dynamic tO = t[i];
|
||||
if (!tO.Equals(whereColumnEquals))
|
||||
{
|
||||
t = reader.NextRecord(throwOnParsingError);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var interceptor = new Enumerable.DBFInterceptor(t, props);
|
||||
|
||||
|
||||
tReturn.Add(interceptor);
|
||||
t = reader.NextRecord(throwOnParsingError);
|
||||
}
|
||||
|
||||
|
||||
return tReturn;
|
||||
}
|
||||
}
|
||||
}
|
||||
128
DotNetDBF.Enumerable/Obsolete.cs
Normal file
128
DotNetDBF.Enumerable/Obsolete.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
// ReSharper disable StringLiteralTypo
|
||||
// ReSharper disable IdentifierTypo
|
||||
|
||||
|
||||
namespace DotNetDBF.Enumerable
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface to get the contents of the DBF Wrapper
|
||||
/// </summary>
|
||||
///
|
||||
[Obsolete("DotNetDBF.Enumerable.IDBFInterceptor is the new interface name",error:true)]
|
||||
public interface IDBFIntercepter:IDBFInterceptor
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
[Obsolete("DotNetDBF.Enumerable.DBFInterceptor is the new class name")]
|
||||
public class DBFIntercepter : DBFEnumerable.DBFIntercepter
|
||||
{
|
||||
public DBFIntercepter(object[] wrappedObj, string[] fieldNames) : base(wrappedObj, fieldNames)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace DotNetDBF.Enumerable
|
||||
{
|
||||
public static partial class DBFEnumerable
|
||||
{
|
||||
[Obsolete("DotNetDBF.Enumerable.IDBFIntercepter is the new interface name")]
|
||||
public interface IDBFIntercepter : DotNetDBF.Enumerable.IDBFIntercepter
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("DotNetDBF.Enumerable.DBFIntercepter is the new class name")]
|
||||
public class DBFIntercepter : DotNetDBF.Enumerable.Enuemrable.DBFIntercepter, IDBFIntercepter
|
||||
{
|
||||
public DBFIntercepter(object[] wrappedObj, string[] fieldNames)
|
||||
: base(wrappedObj, fieldNames)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Obsolete("DBFEnumerable is the new class name")]
|
||||
public static class Enuemrable
|
||||
{
|
||||
/// <summary>
|
||||
/// New Blank Row Dynamic object that matches writer;
|
||||
/// </summary>
|
||||
/// <param name="writer">The writer.</param>
|
||||
/// <returns></returns>
|
||||
public static dynamic NewBlankRow(DBFWriter writer)
|
||||
{
|
||||
return writer.NewBlankRow();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Writes the record.
|
||||
/// </summary>
|
||||
/// <param name="writer">The writer.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
public static void WriteRecord(DBFWriter writer, IDBFIntercepter value)
|
||||
{
|
||||
writer.WriteRecord(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the record.
|
||||
/// </summary>
|
||||
/// <param name="writer">The writer.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
public static void AddRecord(DBFWriter writer, IDBFIntercepter value)
|
||||
{
|
||||
writer.AddRecord(writer, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return all the records. T should be interface with getter properties that match types and names of the database.
|
||||
/// Optionally instead of T being and interface you can pass in an anonymous object with properties that match that
|
||||
/// database and then you'll get an IEnumerable of that anonymous type with the data filled in.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="prototype">The prototype. Anonymous class instance</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> AllRecords<T>(DBFReader reader, T prototype = null) where T : class
|
||||
{
|
||||
return reader.AllRecords(prototype);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of dynamic objects whose properties and types match up with that database name.
|
||||
/// </summary>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="whereColumn">The where column name.</param>
|
||||
/// <param name="whereColumnEquals">What the were column should equal.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<dynamic> DynamicAllRecords(DBFReader reader, string whereColumn = null,
|
||||
dynamic whereColumnEquals = null)
|
||||
{
|
||||
return reader.DynamicAllRecords(whereColumn, (object) whereColumnEquals);
|
||||
}
|
||||
|
||||
|
||||
[Obsolete("DotNetDBF.Enumerable.IDBFIntercepter is the new interface name",error:true)]
|
||||
public interface IDBFIntercepter : DotNetDBF.Enumerable.IDBFInterceptor
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("DotNetDBF.Enumerable.DBFIntercepter is the new class name")]
|
||||
public class DBFIntercepter : DotNetDBF.Enumerable.BaseDBFInterceptor, IDBFIntercepter
|
||||
{
|
||||
public DBFIntercepter(object[] wrappedObj, string[] fieldNames)
|
||||
: base(wrappedObj, fieldNames)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
DotNetDBF.Enumerable/sn.snk
Normal file
BIN
DotNetDBF.Enumerable/sn.snk
Normal file
Binary file not shown.
43
DotNetDBF.Test/DotNetDBF.Test.csproj
Normal file
43
DotNetDBF.Test/DotNetDBF.Test.csproj
Normal file
@@ -0,0 +1,43 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp2.0;net462</TargetFrameworks>
|
||||
<OutputType Condition="'$(TargetFramework)'!='netcoreapp2.0'">Exe</OutputType>
|
||||
<Copyright>Copyright © 2017</Copyright>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NUnit" Version="3.7.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.8.*" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.*" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="dbfs\cp1251.dbf" />
|
||||
<EmbeddedResource Include="dbfs\dbase_03.dbf" />
|
||||
<EmbeddedResource Include="dbfs\dbase_30.dbf" />
|
||||
<EmbeddedResource Include="dbfs\dbase_30.fpt" />
|
||||
<EmbeddedResource Include="dbfs\dbase_31.dbf" />
|
||||
<EmbeddedResource Include="dbfs\dbase_83.dbf" />
|
||||
<EmbeddedResource Include="dbfs\dbase_83.dbt" />
|
||||
<EmbeddedResource Include="dbfs\dbase_83_missing_memo.dbf" />
|
||||
<EmbeddedResource Include="dbfs\dbase_83_missing_memo_record_0.yml" />
|
||||
<EmbeddedResource Include="dbfs\dbase_83_record_0.yml" />
|
||||
<EmbeddedResource Include="dbfs\dbase_83_record_9.yml" />
|
||||
<EmbeddedResource Include="dbfs\dbase_8b.dbf" />
|
||||
<EmbeddedResource Include="dbfs\dbase_8b.dbt" />
|
||||
<EmbeddedResource Include="dbfs\dbase_f5.dbf" />
|
||||
<EmbeddedResource Include="dbfs\dbase_f5.fpt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DotNetDBF.Enumerable\DotNetDBF.Enumerable.csproj" />
|
||||
<ProjectReference Include="..\DotNetDBF\DotNetDBF.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="dbfs\cp1251_summary.txt" />
|
||||
<EmbeddedResource Include="dbfs\dbase_03_summary.txt" />
|
||||
<EmbeddedResource Include="dbfs\dbase_30_summary.txt" />
|
||||
<EmbeddedResource Include="dbfs\dbase_31_summary.txt" />
|
||||
<EmbeddedResource Include="dbfs\dbase_83_schema.txt" />
|
||||
<EmbeddedResource Include="dbfs\dbase_83_summary.txt" />
|
||||
<EmbeddedResource Include="dbfs\dbase_8b_summary.txt" />
|
||||
<EmbeddedResource Include="dbfs\dbase_f5_summary.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
31
DotNetDBF.Test/Issue19Test.cs
Normal file
31
DotNetDBF.Test/Issue19Test.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotNetDBF.Test
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class Issue19Test
|
||||
{
|
||||
private Stream DbfsData(string filename) => typeof(Issue19Test).Assembly
|
||||
.GetManifestResourceStream($"{nameof(DotNetDBF)}.{nameof(Test)}.dbfs.{filename}");
|
||||
|
||||
[Test]
|
||||
public void ReadTest()
|
||||
{
|
||||
using (var dbfstream = DbfsData("dbase_8b.dbf"))
|
||||
using (var memoStream = DbfsData("dbase_8b.dbt"))
|
||||
using (DBFReader dbfr = new DBFReader(dbfstream) { DataMemo = memoStream})
|
||||
{
|
||||
object[] record = dbfr.NextRecord();
|
||||
//This line would hang issue #19 https://github.com/ekonbenefits/dotnetdbf/issues/19
|
||||
Assert.Throws<DBTException>(() => record[5].ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
DotNetDBF.Test/Program.cs
Normal file
16
DotNetDBF.Test/Program.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace DotNetDBF.Test
|
||||
{
|
||||
#if !NETCOREAPP2_0
|
||||
public class Program
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
11
DotNetDBF.Test/Properties/AssemblyInfo.cs
Normal file
11
DotNetDBF.Test/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("8d5436e3-f584-40a0-acdc-65346eceadb0")]
|
||||
544
DotNetDBF.Test/Test.cs
Normal file
544
DotNetDBF.Test/Test.cs
Normal file
@@ -0,0 +1,544 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using DotNetDBF;
|
||||
using DotNetDBF.Enumerable;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotNetDBFTest
|
||||
{
|
||||
public interface ITestInterface
|
||||
{
|
||||
string F1 { get; set; }
|
||||
|
||||
string F2 { get; set; }
|
||||
|
||||
string F3 { get; set; }
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class DotNetDBFTest : AssertionHelper
|
||||
{
|
||||
private string TestPath([CallerMemberName] string name = null)
|
||||
=> Path.Combine(Path.GetTempPath(), name + "_121212.dbf");
|
||||
|
||||
private string TestRAFPath([CallerMemberName] string name = null)
|
||||
=> Path.Combine(Path.GetTempPath(), name + "_raf-1212.dbf");
|
||||
|
||||
|
||||
private string TestClipLongPath([CallerMemberName] string name = null)
|
||||
=> Path.Combine(Path.GetTempPath(), name + "_cliplong.dbf");
|
||||
|
||||
private string TestMemoPath([CallerMemberName] string name = null)
|
||||
=> Path.Combine(Path.GetTempPath(), name + "_clipmemo.dbf");
|
||||
|
||||
private string TestSelectPath([CallerMemberName] string name = null)
|
||||
=> Path.Combine(Path.GetTempPath(), name + "_select.dbf");
|
||||
|
||||
private string GetCharacters(int aLength)
|
||||
{
|
||||
var chars = new[] {"a", "b", "c", "d", "e", "f", "g", " "};
|
||||
var returnval = string.Join(string.Empty,
|
||||
Enumerable.Range(0, aLength).Select(it => chars[it % chars.Length]).ToArray());
|
||||
Assert.That(returnval.Length, EqualTo(aLength), "GetCharacters() did not return correct length string");
|
||||
return returnval;
|
||||
}
|
||||
|
||||
|
||||
private static void println(String s)
|
||||
{
|
||||
Console.WriteLine(s);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void checkDataType_N()
|
||||
{
|
||||
Decimal writtenValue;
|
||||
using (
|
||||
Stream fos =
|
||||
File.Open(TestPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
using (var writer = new DBFWriter())
|
||||
{
|
||||
var field = new DBFField("F1", NativeDbType.Numeric, 15, 0);
|
||||
writer.Fields = new[] {field};
|
||||
|
||||
writtenValue = 123456789012345L;
|
||||
writer.AddRecord(writtenValue);
|
||||
writer.Write(fos);
|
||||
}
|
||||
using (
|
||||
Stream fis =
|
||||
File.Open(TestPath(),
|
||||
FileMode.Open,
|
||||
FileAccess.Read))
|
||||
using (var reader = new DBFReader(fis))
|
||||
{
|
||||
var readValues = reader.NextRecord();
|
||||
|
||||
Assert.That(readValues[0], EqualTo(writtenValue), "Written Value Equals Read");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void checkLongCharLengthWithClipper()
|
||||
{
|
||||
var fieldLength = 750;
|
||||
string writtenValue;
|
||||
using (
|
||||
Stream fos =
|
||||
File.Open(TestClipLongPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
{
|
||||
var writer = new DBFWriter();
|
||||
var field = new DBFField("F1", NativeDbType.Char, fieldLength);
|
||||
writer.Fields = new[] {field};
|
||||
|
||||
writtenValue = GetCharacters(fieldLength);
|
||||
writer.AddRecord(writtenValue);
|
||||
writer.Write(fos);
|
||||
}
|
||||
using (
|
||||
Stream fis =
|
||||
File.Open(TestClipLongPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
{
|
||||
var reader = new DBFReader(fis);
|
||||
Assert.That(reader.Fields.First().FieldLength, EqualTo(fieldLength));
|
||||
var readValues = reader.NextRecord();
|
||||
|
||||
Assert.That(readValues[0], EqualTo(writtenValue), "Written Value not equaling Read");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void checkDataType_M()
|
||||
{
|
||||
var fieldLength = 2400;
|
||||
MemoValue writtenValue;
|
||||
using (Stream fos = File.Open(TestMemoPath(), FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||||
using (var writer = new DBFWriter
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestMemoPath(), "DBT")
|
||||
})
|
||||
{
|
||||
var field = new DBFField("F1", NativeDbType.Memo);
|
||||
writer.Fields = new[] {field};
|
||||
|
||||
writtenValue = new MemoValue(GetCharacters(fieldLength));
|
||||
writer.AddRecord(writtenValue);
|
||||
writer.Write(fos);
|
||||
}
|
||||
using (Stream fis = File.Open(TestMemoPath(), FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||||
using (var reader = new DBFReader(fis)
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestMemoPath(), "DBT")
|
||||
})
|
||||
{
|
||||
var readValues = reader.NextRecord();
|
||||
|
||||
Assert.That(readValues[0], EqualTo(writtenValue), "Written Value not equaling Read");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void checkSelect()
|
||||
{
|
||||
var fieldLength = 2400;
|
||||
string writtenValue;
|
||||
using (
|
||||
Stream fos =
|
||||
File.Open(TestSelectPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
{
|
||||
var writer = new DBFWriter
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
};
|
||||
var field = new DBFField("F1", NativeDbType.Memo);
|
||||
var field2 = new DBFField("F2", NativeDbType.Numeric, 10);
|
||||
var field3 = new DBFField("F3", NativeDbType.Char, 10);
|
||||
writer.Fields = new[] {field, field2, field3};
|
||||
|
||||
writtenValue = "alpha";
|
||||
writer.AddRecord(new MemoValue(GetCharacters(fieldLength)), 10, writtenValue);
|
||||
writer.Write(fos);
|
||||
}
|
||||
using (
|
||||
Stream fis =
|
||||
File.Open(TestSelectPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
{
|
||||
var reader = new DBFReader(fis)
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
};
|
||||
reader.SetSelectFields("F3");
|
||||
var readValues = reader.NextRecord();
|
||||
|
||||
Assert.That(readValues[0], StartsWith(writtenValue), "Written Value not equaling Read");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void checkSelectDynamic()
|
||||
{
|
||||
var fieldLength = 2400;
|
||||
string writtenValue;
|
||||
string writtenMemo;
|
||||
using (
|
||||
Stream fos =
|
||||
File.Open(TestSelectPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
using (var writer = new DBFWriter
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
})
|
||||
{
|
||||
var field = new DBFField("F1", NativeDbType.Memo);
|
||||
var field2 = new DBFField("F2", NativeDbType.Numeric, 10);
|
||||
var field3 = new DBFField("F3", NativeDbType.Char, 10);
|
||||
writer.Fields = new[] {field, field2, field3};
|
||||
|
||||
writtenValue = "alpha";
|
||||
writtenMemo = GetCharacters(fieldLength);
|
||||
writer.AddRecord(new MemoValue(writtenMemo), 10, writtenValue);
|
||||
writer.Write(fos);
|
||||
}
|
||||
using (
|
||||
Stream fis =
|
||||
File.Open(TestSelectPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
using (var reader = new DBFReader(fis)
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
})
|
||||
{
|
||||
reader.SetSelectFields("F1", "F3");
|
||||
var readValues = reader.DynamicAllRecords().First();
|
||||
|
||||
Assert.That(readValues.F1.ToString(), EqualTo(writtenMemo), "Written Value not equaling Read");
|
||||
Assert.That(readValues.F3, EqualTo(writtenValue), "Written Value not equaling Read");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void checkAnnoymous()
|
||||
{
|
||||
var fieldLength = 2400;
|
||||
string writtenValue;
|
||||
using (
|
||||
Stream fos =
|
||||
File.Open(TestSelectPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
{
|
||||
var writer = new DBFWriter
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
};
|
||||
var field = new DBFField("F1", NativeDbType.Memo);
|
||||
var field2 = new DBFField("F2", NativeDbType.Numeric, 10);
|
||||
var field3 = new DBFField("F3", NativeDbType.Char, 10);
|
||||
writer.Fields = new[] {field, field2, field3};
|
||||
|
||||
writtenValue = "alpha";
|
||||
writer.AddRecord(new MemoValue(GetCharacters(fieldLength)), 10, writtenValue);
|
||||
writer.Write(fos);
|
||||
}
|
||||
using (
|
||||
Stream fis =
|
||||
File.Open(TestSelectPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
{
|
||||
var reader = new DBFReader(fis)
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
};
|
||||
|
||||
var readValues = reader.AllRecords(new {F2 = default(decimal), F3 = default(string)});
|
||||
|
||||
Assert.That(readValues.First().F3, StartsWith(writtenValue), "Written Value not equaling Read");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void checkProxy()
|
||||
{
|
||||
var fieldLength = 2400;
|
||||
string writtenValue;
|
||||
using (
|
||||
Stream fos =
|
||||
File.Open(TestSelectPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
{
|
||||
using (var writer = new DBFWriter {
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
})
|
||||
{
|
||||
|
||||
;
|
||||
var field = new DBFField("F1", NativeDbType.Memo);
|
||||
var field2 = new DBFField("F2", NativeDbType.Numeric, 10);
|
||||
var field3 = new DBFField("F3", NativeDbType.Char, 10);
|
||||
writer.Fields = new[] {field, field2, field3};
|
||||
|
||||
writtenValue = "alpha";
|
||||
writer.AddRecord(new MemoValue(GetCharacters(fieldLength)), 10, writtenValue);
|
||||
writer.Write(fos);
|
||||
}
|
||||
}
|
||||
using (
|
||||
Stream fis =
|
||||
File.Open(TestSelectPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
{
|
||||
using (var reader = new DBFReader(fis)
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
})
|
||||
{
|
||||
|
||||
var readValues = reader.AllRecords<ITestInterface>();
|
||||
|
||||
Assert.That(readValues.First().F3, StartsWith(writtenValue), "Written Value not equaling Read");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void checkDynamicProxy()
|
||||
{
|
||||
var fieldLength = 2400;
|
||||
string writtenValue;
|
||||
using (
|
||||
Stream fos =
|
||||
File.Open(TestSelectPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
using (var writer = new DBFWriter
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
})
|
||||
{
|
||||
var field = new DBFField("F1", NativeDbType.Memo);
|
||||
var field2 = new DBFField("F2", NativeDbType.Numeric, 10);
|
||||
var field3 = new DBFField("F3", NativeDbType.Char, 10);
|
||||
writer.Fields = new[] {field, field2, field3};
|
||||
|
||||
writtenValue = "alpha";
|
||||
writer.AddRecord(new MemoValue(GetCharacters(fieldLength)), 10, writtenValue);
|
||||
writer.Write(fos);
|
||||
}
|
||||
using (
|
||||
Stream fis =
|
||||
File.Open(TestSelectPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
using (var reader = new DBFReader(fis)
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
})
|
||||
{
|
||||
var readValues = reader.DynamicAllRecords();
|
||||
|
||||
Assert.That(readValues.First().F3, StartsWith(writtenValue), "Written Value not equaling Read");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void checkDynamicProxyWhere()
|
||||
{
|
||||
var fieldLength = 2400;
|
||||
string writtenValue;
|
||||
using (
|
||||
Stream fos =
|
||||
File.Open(TestSelectPath(),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
using (var writer = new DBFWriter
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
})
|
||||
{
|
||||
var field = new DBFField("F1", NativeDbType.Memo);
|
||||
var field2 = new DBFField("F2", NativeDbType.Numeric, 10);
|
||||
var field3 = new DBFField("F3", NativeDbType.Char, 10);
|
||||
writer.Fields = new[] {field, field2, field3};
|
||||
|
||||
writtenValue = "alpha";
|
||||
writer.AddRecord(new MemoValue(GetCharacters(fieldLength)), 10, writtenValue);
|
||||
|
||||
writer.AddRecord(new MemoValue(GetCharacters(fieldLength)), 12, "beta");
|
||||
|
||||
writer.Write(fos);
|
||||
}
|
||||
|
||||
using (var reader = new DBFReader(TestSelectPath())
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
})
|
||||
{
|
||||
var readValues = reader.DynamicAllRecords();
|
||||
|
||||
Assert.That(Equals(readValues.Count(), 2), "All Records not matching");
|
||||
}
|
||||
|
||||
using (var reader = new DBFReader(TestSelectPath())
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
})
|
||||
{
|
||||
var readValues = reader.DynamicAllRecords(whereColumn: "F2", whereColumnEquals: 10);
|
||||
|
||||
Assert.That(Equals(readValues.Count(), 1), "All Records not matching");
|
||||
}
|
||||
|
||||
using (var reader = new DBFReader(TestSelectPath())
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
})
|
||||
{
|
||||
var readValues = reader.DynamicAllRecords(whereColumn: "F2", whereColumnEquals: 12);
|
||||
|
||||
Assert.That(Equals(readValues.Count(), 1), "All Records not matching");
|
||||
}
|
||||
using (var reader = new DBFReader(TestSelectPath())
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(TestSelectPath(), "DBT")
|
||||
})
|
||||
{
|
||||
var readValues = reader.DynamicAllRecords(whereColumn: "F2", whereColumnEquals: 13);
|
||||
|
||||
Assert.That(Equals(readValues.Count(), 0), "All Records not matching");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void checkRAFwriting()
|
||||
{
|
||||
println("Writing in RAF mode ... ");
|
||||
|
||||
if (File.Exists(TestRAFPath()))
|
||||
{
|
||||
File.Delete(TestRAFPath());
|
||||
}
|
||||
using (var writer = new DBFWriter(TestRAFPath()))
|
||||
{
|
||||
var fields = new DBFField[2];
|
||||
|
||||
fields[0] = new DBFField("F1", NativeDbType.Char, 10);
|
||||
|
||||
fields[1] = new DBFField("F2", NativeDbType.Numeric, 2);
|
||||
|
||||
writer.Fields = fields;
|
||||
|
||||
|
||||
writer.WriteRecord("Red", 10);
|
||||
writer.WriteRecord("Blue", 20);
|
||||
}
|
||||
|
||||
println("done.");
|
||||
|
||||
println("Appending to this file");
|
||||
|
||||
using (var writer = new DBFWriter(TestRAFPath()))
|
||||
{
|
||||
writer.WriteRecord("Green", 33);
|
||||
|
||||
writer.WriteRecord("Yellow", 44);
|
||||
}
|
||||
println("done.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShowPaths()
|
||||
{
|
||||
println(TestPath());
|
||||
|
||||
println(TestRAFPath());
|
||||
|
||||
println(TestClipLongPath());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test()
|
||||
{
|
||||
using (
|
||||
Stream fis =
|
||||
File.Open(@"f:\st\dev\testdata\p.dbf",
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
using (var reader = new DBFReader(fis)
|
||||
{
|
||||
DataMemoLoc = Path.ChangeExtension(@"f:\st\dev\testdata\p.dbf", "DBT")
|
||||
})
|
||||
{
|
||||
var readValues = reader.NextRecord();
|
||||
|
||||
Console.WriteLine(readValues);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void test1()
|
||||
{
|
||||
Assert.DoesNotThrow(() => { new DBFWriter(); }, "Can't Create empty DBFWriter Object");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void test2()
|
||||
{
|
||||
Assert.DoesNotThrow(() => { new DBFField(); }, "Can't Create empty DBFWriter Object");
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void test3()
|
||||
{
|
||||
WriteSample();
|
||||
ReadSample();
|
||||
}
|
||||
|
||||
public void WriteSample([CallerMemberName] string name = null)
|
||||
{
|
||||
var field = new DBFField {Name = "F1", DataType = NativeDbType.Numeric};
|
||||
var writer = new DBFWriter {Fields = new[] {field}};
|
||||
writer.AddRecord(3);
|
||||
using (
|
||||
Stream fos =
|
||||
File.Open(TestPath(name),
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite))
|
||||
{
|
||||
writer.Write(fos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ReadSample([CallerMemberName] string name = null)
|
||||
{
|
||||
using (var reader = new DBFReader(TestPath(name)))
|
||||
{
|
||||
Assert.That(reader.RecordCount, EqualTo(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
DotNetDBF.Test/dbfs/Readme.md
Normal file
22
DotNetDBF.Test/dbfs/Readme.md
Normal file
@@ -0,0 +1,22 @@
|
||||
Most of the DBFs here are from the spec directory of the dbf ruby gem
|
||||
|
||||
Copyright (c) 2006-2017 Keith Morrison <keithm@infused.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS 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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
BIN
DotNetDBF.Test/dbfs/cp1251.dbf
Normal file
BIN
DotNetDBF.Test/dbfs/cp1251.dbf
Normal file
Binary file not shown.
11
DotNetDBF.Test/dbfs/cp1251_summary.txt
Normal file
11
DotNetDBF.Test/dbfs/cp1251_summary.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
Database: cp1251.dbf
|
||||
Type: (30) Visual FoxPro
|
||||
Memo File: false
|
||||
Records: 4
|
||||
|
||||
Fields:
|
||||
Name Type Length Decimal
|
||||
------------------------------------------------------------------------------
|
||||
RN N 4 0
|
||||
NAME C 100 0
|
||||
BIN
DotNetDBF.Test/dbfs/dbase_03.dbf
Normal file
BIN
DotNetDBF.Test/dbfs/dbase_03.dbf
Normal file
Binary file not shown.
40
DotNetDBF.Test/dbfs/dbase_03_summary.txt
Normal file
40
DotNetDBF.Test/dbfs/dbase_03_summary.txt
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
Database: dbase_03.dbf
|
||||
Type: (03) dBase III without memo file
|
||||
Memo File: false
|
||||
Records: 14
|
||||
|
||||
Fields:
|
||||
Name Type Length Decimal
|
||||
------------------------------------------------------------------------------
|
||||
Point_ID C 12 0
|
||||
Type C 20 0
|
||||
Shape C 20 0
|
||||
Circular_D C 20 0
|
||||
Non_circul C 60 0
|
||||
Flow_prese C 20 0
|
||||
Condition C 20 0
|
||||
Comments C 60 0
|
||||
Date_Visit D 8 0
|
||||
Time C 10 0
|
||||
Max_PDOP N 5 1
|
||||
Max_HDOP N 5 1
|
||||
Corr_Type C 36 0
|
||||
Rcvr_Type C 36 0
|
||||
GPS_Date D 8 0
|
||||
GPS_Time C 10 0
|
||||
Update_Sta C 36 0
|
||||
Feat_Name C 20 0
|
||||
Datafile C 20 0
|
||||
Unfilt_Pos N 10 0
|
||||
Filt_Pos N 10 0
|
||||
Data_Dicti C 20 0
|
||||
GPS_Week N 6 0
|
||||
GPS_Second N 12 3
|
||||
GPS_Height N 16 3
|
||||
Vert_Prec N 16 1
|
||||
Horz_Prec N 16 1
|
||||
Std_Dev N 16 6
|
||||
Northing N 16 3
|
||||
Easting N 16 3
|
||||
Point_ID N 9 0
|
||||
BIN
DotNetDBF.Test/dbfs/dbase_30.dbf
Normal file
BIN
DotNetDBF.Test/dbfs/dbase_30.dbf
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/dbase_30.fpt
Normal file
BIN
DotNetDBF.Test/dbfs/dbase_30.fpt
Normal file
Binary file not shown.
154
DotNetDBF.Test/dbfs/dbase_30_summary.txt
Normal file
154
DotNetDBF.Test/dbfs/dbase_30_summary.txt
Normal file
@@ -0,0 +1,154 @@
|
||||
|
||||
Database: dbase_30.dbf
|
||||
Type: (30) Visual FoxPro
|
||||
Memo File: true
|
||||
Records: 34
|
||||
|
||||
Fields:
|
||||
Name Type Length Decimal
|
||||
------------------------------------------------------------------------------
|
||||
ACCESSNO C 15 0
|
||||
ACQVALUE N 12 2
|
||||
APPNOTES M 4 0
|
||||
APPRAISOR C 75 0
|
||||
CABINET C 25 0
|
||||
CAPTION C 30 0
|
||||
CAT C 1 0
|
||||
CATBY C 25 0
|
||||
CATDATE D 8 0
|
||||
CATTYPE C 15 0
|
||||
CLASSES M 4 0
|
||||
COLLECTION C 75 0
|
||||
CONDDATE D 8 0
|
||||
CONDEXAM C 25 0
|
||||
CONDITION C 35 0
|
||||
CONDNOTES M 4 0
|
||||
CONTAINER C 40 0
|
||||
COPYRIGHT M 4 0
|
||||
CREATOR C 80 0
|
||||
CREDIT M 4 0
|
||||
CURVALMAX N 12 2
|
||||
CURVALUE N 12 2
|
||||
DATASET C 15 0
|
||||
DATE C 50 0
|
||||
DESCRIP M 4 0
|
||||
DIMNOTES M 4 0
|
||||
DISPVALUE C 10 0
|
||||
DRAWER C 20 0
|
||||
EARLYDATE N 4 0
|
||||
EVENT C 80 0
|
||||
EXHIBITID C 36 0
|
||||
EXHIBITNO N 7 0
|
||||
EXHLABEL1 M 4 0
|
||||
EXHLABEL2 M 4 0
|
||||
EXHLABEL3 M 4 0
|
||||
EXHLABEL4 M 4 0
|
||||
EXHSTART D 8 0
|
||||
FILMSIZE C 35 0
|
||||
FLAGDATE T 8 0
|
||||
FLAGNOTES M 4 0
|
||||
FLAGREASON C 20 0
|
||||
FRAME C 75 0
|
||||
FRAMENO C 25 0
|
||||
GPARENT C 45 0
|
||||
HOMELOC C 60 0
|
||||
IMAGEFILE C 60 0
|
||||
IMAGENO N 3 0
|
||||
INSCOMP C 30 0
|
||||
INSDATE D 8 0
|
||||
INSPHONE C 25 0
|
||||
INSPREMIUM C 20 0
|
||||
INSREP C 30 0
|
||||
INSVALUE N 10 2
|
||||
INVNBY C 25 0
|
||||
INVNDATE D 8 0
|
||||
LATEDATE N 4 0
|
||||
LEGAL M 4 0
|
||||
LOANCOND M 4 0
|
||||
LOANDATE D 8 0
|
||||
LOANDUE D 8 0
|
||||
LOANID C 36 0
|
||||
LOANINNO C 15 0
|
||||
MAINTCYCLE C 10 0
|
||||
MAINTDATE D 8 0
|
||||
MAINTNOTE M 4 0
|
||||
MEDIUM C 75 0
|
||||
NEGLOC C 60 0
|
||||
NEGNO C 25 0
|
||||
NOTES M 4 0
|
||||
OBJECTID C 25 0
|
||||
OBJNAME C 40 0
|
||||
OLDNO C 25 0
|
||||
ORIGCOPY C 15 0
|
||||
OTHERNO C 25 0
|
||||
OUTDATE D 8 0
|
||||
PARENT C 40 0
|
||||
PEOPLE M 4 0
|
||||
PLACE C 100 0
|
||||
POLICYNO C 20 0
|
||||
PRINTSIZE C 35 0
|
||||
PROCESS C 75 0
|
||||
PROVENANCE M 4 0
|
||||
PUBNOTES M 4 0
|
||||
RECAS C 20 0
|
||||
RECDATE C 10 0
|
||||
RECFROM C 120 0
|
||||
RELATION C 36 0
|
||||
RELNOTES M 4 0
|
||||
ROOM C 25 0
|
||||
SGFLAG C 1 0
|
||||
SHELF C 20 0
|
||||
SITE C 40 0
|
||||
SITENO C 12 0
|
||||
SLIDENO C 25 0
|
||||
STATUS C 20 0
|
||||
STATUSBY C 25 0
|
||||
STATUSDATE D 8 0
|
||||
STERMS M 4 0
|
||||
STUDIO C 60 0
|
||||
SUBJECTS M 4 0
|
||||
TCABINET C 25 0
|
||||
TCONTAINER C 40 0
|
||||
TDRAWER C 20 0
|
||||
TEMPAUTHOR C 25 0
|
||||
TEMPBY C 25 0
|
||||
TEMPDATE D 8 0
|
||||
TEMPLOC C 60 0
|
||||
TEMPNOTES M 4 0
|
||||
TEMPREASON C 50 0
|
||||
TEMPUNTIL C 10 0
|
||||
TITLE M 4 0
|
||||
TITLESORT C 100 0
|
||||
TROOM C 25 0
|
||||
TSHELF C 20 0
|
||||
TWALL C 20 0
|
||||
UDF1 C 75 0
|
||||
UDF10 C 75 0
|
||||
UDF11 C 20 0
|
||||
UDF12 C 20 0
|
||||
UDF13 N 12 0
|
||||
UDF14 N 12 2
|
||||
UDF15 N 12 2
|
||||
UDF16 N 12 3
|
||||
UDF17 N 12 3
|
||||
UDF18 D 8 0
|
||||
UDF19 D 8 0
|
||||
UDF20 D 8 0
|
||||
UDF21 M 4 0
|
||||
UDF22 M 4 0
|
||||
UDF2 C 75 0
|
||||
UDF3 C 75 0
|
||||
UDF4 C 75 0
|
||||
UDF5 C 75 0
|
||||
UDF6 C 75 0
|
||||
UDF7 C 75 0
|
||||
UDF8 C 75 0
|
||||
UDF9 C 75 0
|
||||
UPDATED T 8 0
|
||||
UPDATEDBY C 25 0
|
||||
VALUEDATE D 8 0
|
||||
WALL C 20 0
|
||||
WEBINCLUDE L 1 0
|
||||
ZSORTER C 69 0
|
||||
ZSORTERX C 44 0
|
||||
PPID C 36 0
|
||||
BIN
DotNetDBF.Test/dbfs/dbase_31.dbf
Normal file
BIN
DotNetDBF.Test/dbfs/dbase_31.dbf
Normal file
Binary file not shown.
20
DotNetDBF.Test/dbfs/dbase_31_summary.txt
Normal file
20
DotNetDBF.Test/dbfs/dbase_31_summary.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
Database: dbase_31.dbf
|
||||
Type: (31) Visual FoxPro with AutoIncrement field
|
||||
Memo File: false
|
||||
Records: 77
|
||||
|
||||
Fields:
|
||||
Name Type Length Decimal
|
||||
------------------------------------------------------------------------------
|
||||
PRODUCTID I 4 0
|
||||
PRODUCTNAM C 40 0
|
||||
SUPPLIERID I 4 0
|
||||
CATEGORYID I 4 0
|
||||
QUANTITYPE C 20 0
|
||||
UNITPRICE Y 8 4
|
||||
UNITSINSTO I 4 0
|
||||
UNITSONORD I 4 0
|
||||
REORDERLEV I 4 0
|
||||
DISCONTINU L 1 0
|
||||
_NullFlags 0 1 0
|
||||
BIN
DotNetDBF.Test/dbfs/dbase_83.dbf
Normal file
BIN
DotNetDBF.Test/dbfs/dbase_83.dbf
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/dbase_83.dbt
Normal file
BIN
DotNetDBF.Test/dbfs/dbase_83.dbt
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/dbase_83_missing_memo.dbf
Normal file
BIN
DotNetDBF.Test/dbfs/dbase_83_missing_memo.dbf
Normal file
Binary file not shown.
16
DotNetDBF.Test/dbfs/dbase_83_missing_memo_record_0.yml
Normal file
16
DotNetDBF.Test/dbfs/dbase_83_missing_memo_record_0.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- 87
|
||||
- 2
|
||||
- 0
|
||||
- 0
|
||||
- 87
|
||||
- '1'
|
||||
- Assorted Petits Fours
|
||||
- graphics/00000001/t_1.jpg
|
||||
- graphics/00000001/1.jpg
|
||||
- 0.0
|
||||
- 0.0
|
||||
-
|
||||
- 5.51
|
||||
- true
|
||||
- true
|
||||
16
DotNetDBF.Test/dbfs/dbase_83_record_0.yml
Normal file
16
DotNetDBF.Test/dbfs/dbase_83_record_0.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- 87
|
||||
- 2
|
||||
- 0
|
||||
- 0
|
||||
- 87
|
||||
- '1'
|
||||
- Assorted Petits Fours
|
||||
- graphics/00000001/t_1.jpg
|
||||
- graphics/00000001/1.jpg
|
||||
- 0.0
|
||||
- 0.0
|
||||
- "Our Original assortment...a little taste of heaven for everyone. Let us\r\nselect a special assortment of our chocolate and pastel favorites for you.\r\nEach petit four is its own special hand decorated creation. Multi-layers of\r\nmoist cake with combinations of specialty fillings create memorable cake\r\nconfections. Varietes include; Luscious Lemon, Strawberry Hearts, White\r\nChocolate, Mocha Bean, Roasted Almond, Triple Chocolate, Chocolate Hazelnut,\r\nGrand Orange, Plum Squares, Milk chocolate squares, and Raspberry Blanc."
|
||||
- 5.51
|
||||
- true
|
||||
- true
|
||||
23
DotNetDBF.Test/dbfs/dbase_83_record_9.yml
Normal file
23
DotNetDBF.Test/dbfs/dbase_83_record_9.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
- 34
|
||||
- 1
|
||||
- 0
|
||||
- 0
|
||||
- 34
|
||||
- AB01
|
||||
- Apricot Brandy Fruitcake
|
||||
- graphics/00000001/t_AB01.jpg
|
||||
- graphics/00000001/AB01.jpg
|
||||
- 37.95
|
||||
- 37.95
|
||||
- "Once tasted you will understand why we won The\r\nBoston Herald's Fruitcake Taste-off.
|
||||
Judges liked its generous size,\r\nluscious appearance, moist texture and fruit
|
||||
to cake ratio ... commented one\r\njudge \"It's a lip Smacker!\" Our signature fruitcake
|
||||
is baked with carefully\r\nselected ingredients that will be savored until the last
|
||||
moist crumb is\r\ndevoured each golden slice is brimming with Australian glaced
|
||||
apricots,\r\ntoasted pecans, candied orange peel, and currants, folded gently into
|
||||
a\r\nbrandy butter batter and slowly baked to perfection and then generously\r\nimbibed
|
||||
with \"Holiday Spirits\". Presented in a gift tin. (3lbs. 4oz)"
|
||||
- 0.0
|
||||
- false
|
||||
- true
|
||||
19
DotNetDBF.Test/dbfs/dbase_83_schema.txt
Normal file
19
DotNetDBF.Test/dbfs/dbase_83_schema.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
ActiveRecord::Schema.define do
|
||||
create_table "dbase_83" do |t|
|
||||
t.column "id", :integer
|
||||
t.column "catcount", :integer
|
||||
t.column "agrpcount", :integer
|
||||
t.column "pgrpcount", :integer
|
||||
t.column "order", :integer
|
||||
t.column "code", :string, :limit => 50
|
||||
t.column "name", :string, :limit => 100
|
||||
t.column "thumbnail", :string, :limit => 254
|
||||
t.column "image", :string, :limit => 254
|
||||
t.column "price", :float
|
||||
t.column "cost", :float
|
||||
t.column "desc", :text
|
||||
t.column "weight", :float
|
||||
t.column "taxable", :boolean
|
||||
t.column "active", :boolean
|
||||
end
|
||||
end
|
||||
24
DotNetDBF.Test/dbfs/dbase_83_summary.txt
Normal file
24
DotNetDBF.Test/dbfs/dbase_83_summary.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
Database: dbase_83.dbf
|
||||
Type: (83) dBase III with memo file
|
||||
Memo File: true
|
||||
Records: 67
|
||||
|
||||
Fields:
|
||||
Name Type Length Decimal
|
||||
------------------------------------------------------------------------------
|
||||
ID N 19 0
|
||||
CATCOUNT N 19 0
|
||||
AGRPCOUNT N 19 0
|
||||
PGRPCOUNT N 19 0
|
||||
ORDER N 19 0
|
||||
CODE C 50 0
|
||||
NAME C 100 0
|
||||
THUMBNAIL C 254 0
|
||||
IMAGE C 254 0
|
||||
PRICE N 13 2
|
||||
COST N 13 2
|
||||
DESC M 10 0
|
||||
WEIGHT N 13 2
|
||||
TAXABLE L 1 0
|
||||
ACTIVE L 1 0
|
||||
BIN
DotNetDBF.Test/dbfs/dbase_8b.dbf
Normal file
BIN
DotNetDBF.Test/dbfs/dbase_8b.dbf
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/dbase_8b.dbt
Normal file
BIN
DotNetDBF.Test/dbfs/dbase_8b.dbt
Normal file
Binary file not shown.
15
DotNetDBF.Test/dbfs/dbase_8b_summary.txt
Normal file
15
DotNetDBF.Test/dbfs/dbase_8b_summary.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
Database: dbase_8b.dbf
|
||||
Type: (8b) dBase IV with memo file
|
||||
Memo File: true
|
||||
Records: 10
|
||||
|
||||
Fields:
|
||||
Name Type Length Decimal
|
||||
------------------------------------------------------------------------------
|
||||
CHARACTER C 100 0
|
||||
NUMERICAL N 20 2
|
||||
DATE D 8 0
|
||||
LOGICAL L 1 0
|
||||
FLOAT F 20 18
|
||||
MEMO M 10 0
|
||||
BIN
DotNetDBF.Test/dbfs/dbase_f5.dbf
Normal file
BIN
DotNetDBF.Test/dbfs/dbase_f5.dbf
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/dbase_f5.fpt
Normal file
BIN
DotNetDBF.Test/dbfs/dbase_f5.fpt
Normal file
Binary file not shown.
68
DotNetDBF.Test/dbfs/dbase_f5_summary.txt
Normal file
68
DotNetDBF.Test/dbfs/dbase_f5_summary.txt
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
Database: dbase_f5.dbf
|
||||
Type: (f5) FoxPro with memo file
|
||||
Memo File: true
|
||||
Records: 975
|
||||
|
||||
Fields:
|
||||
Name Type Length Decimal
|
||||
------------------------------------------------------------------------------
|
||||
NF N 5 0
|
||||
SEXE C 1 0
|
||||
NOM C 20 0
|
||||
COG1 C 15 0
|
||||
COG2 C 15 0
|
||||
TELEFON C 9 0
|
||||
RENOM C 15 0
|
||||
NFP N 5 0
|
||||
NFM N 5 0
|
||||
ARXN C 10 0
|
||||
DATN D 8 0
|
||||
LLON C 15 0
|
||||
MUNN C 15 0
|
||||
COMN C 15 0
|
||||
PROV C 15 0
|
||||
PAIN C 15 0
|
||||
OFIC C 15 0
|
||||
ARXB C 10 0
|
||||
DATB D 8 0
|
||||
LLOB C 15 0
|
||||
MUNB C 15 0
|
||||
COMB C 15 0
|
||||
PAIB C 15 0
|
||||
DRIB C 30 0
|
||||
INAB C 30 0
|
||||
OFTB C 10 0
|
||||
OFNB C 20 0
|
||||
AXC1 C 10 0
|
||||
DTC1 D 8 0
|
||||
LLC1 C 15 0
|
||||
NFC1 N 5 0
|
||||
TCA1 C 10 0
|
||||
OTC1 C 10 0
|
||||
ONC1 C 20 0
|
||||
AXC2 C 10 0
|
||||
DTC2 D 8 0
|
||||
LLC2 C 15 0
|
||||
NFC2 N 5 0
|
||||
TCA2 C 10 0
|
||||
OTC2 C 10 0
|
||||
ONC2 C 20 0
|
||||
AXC3 C 10 0
|
||||
DTC3 D 8 0
|
||||
LLC3 C 15 0
|
||||
NFC3 N 5 0
|
||||
TCA3 C 10 0
|
||||
OTC3 C 10 0
|
||||
ONC3 C 20 0
|
||||
ARXD C 10 0
|
||||
DATD D 8 0
|
||||
LLOD C 15 0
|
||||
OFTD C 10 0
|
||||
OFND C 20 0
|
||||
OBS1 C 70 0
|
||||
OBS2 C 70 0
|
||||
OBS3 C 70 0
|
||||
OBS4 C 70 0
|
||||
OBSE M 10 0
|
||||
GHD C 15 0
|
||||
BIN
DotNetDBF.Test/dbfs/foxprodb/FOXPRO-DB-TEST.DBC
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/FOXPRO-DB-TEST.DBC
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/foxprodb/FOXPRO-DB-TEST.DCT
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/FOXPRO-DB-TEST.DCT
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/foxprodb/FOXPRO-DB-TEST.DCX
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/FOXPRO-DB-TEST.DCX
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/foxprodb/calls.CDX
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/calls.CDX
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/foxprodb/calls.FPT
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/calls.FPT
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/foxprodb/calls.dbf
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/calls.dbf
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/foxprodb/contacts.CDX
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/contacts.CDX
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/foxprodb/contacts.FPT
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/contacts.FPT
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/foxprodb/contacts.dbf
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/contacts.dbf
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/foxprodb/setup.CDX
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/setup.CDX
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/foxprodb/setup.dbf
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/setup.dbf
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/foxprodb/types.CDX
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/types.CDX
Normal file
Binary file not shown.
BIN
DotNetDBF.Test/dbfs/foxprodb/types.dbf
Normal file
BIN
DotNetDBF.Test/dbfs/foxprodb/types.dbf
Normal file
Binary file not shown.
9
dotnetdbf/.gitignore
vendored
Normal file
9
dotnetdbf/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
bin
|
||||
obj
|
||||
/packages
|
||||
|
||||
*.suo
|
||||
|
||||
*.user
|
||||
.idea/*
|
||||
.vs/*
|
||||
44
dotnetdbf/DBFBase.cs
Normal file
44
dotnetdbf/DBFBase.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Serves as the base class of DBFReader adn DBFWriter.
|
||||
|
||||
This file is part of DotNetDBF packege.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
Support for choosing implemented character Sets as
|
||||
suggested by Nick Voznesensky <darkers@mail.ru>
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
|
||||
*/
|
||||
/**
|
||||
Base class for DBFReader and DBFWriter.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public abstract class DBFBase
|
||||
{
|
||||
|
||||
public Encoding CharEncoding { get; set; } = Encoding.GetEncoding("utf-8");
|
||||
|
||||
public int BlockSize { get; set; } = 512;
|
||||
|
||||
private string _nullSymbol;
|
||||
public string NullSymbol
|
||||
{
|
||||
get => _nullSymbol ?? DBFFieldType.Unknown;
|
||||
set
|
||||
{
|
||||
if (value != null && value.Length != 1)
|
||||
throw new ArgumentException(nameof(NullSymbol));
|
||||
_nullSymbol = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
62
dotnetdbf/DBFException.cs
Normal file
62
dotnetdbf/DBFException.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
DBFException
|
||||
Represents exceptions happen in the JAvaDBF classes.
|
||||
|
||||
This file is part of DotNetDBF packege.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public class DBTException : DBFException
|
||||
{
|
||||
|
||||
public DBTException(string msg) : base(msg)
|
||||
{
|
||||
}
|
||||
|
||||
public DBTException(string msg, Exception internalException)
|
||||
: base(msg, internalException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class DBFRecordException : DBFException
|
||||
{
|
||||
public int Record { get; }
|
||||
|
||||
public DBFRecordException(string msg, int record) : base(msg)
|
||||
{
|
||||
Record = record;
|
||||
}
|
||||
|
||||
public DBFRecordException(string msg, Exception internalException)
|
||||
: base(msg, internalException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class DBFException : IOException
|
||||
{
|
||||
public DBFException() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public DBFException(string msg) : base(msg)
|
||||
{
|
||||
}
|
||||
|
||||
public DBFException(string msg, Exception internalException)
|
||||
: base(msg, internalException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
309
dotnetdbf/DBFField.cs
Normal file
309
dotnetdbf/DBFField.cs
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
DBFField
|
||||
Class represents a "field" (or column) definition of a DBF data structure.
|
||||
|
||||
This file is part of DotNetDBF packege.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
[DebuggerDisplay("Field:{Name}, Length:{FieldLength}")]
|
||||
public class DBFField
|
||||
{
|
||||
public const int SIZE = 32;
|
||||
public byte dataType; /* 11 */
|
||||
public byte decimalCount; /* 17 */
|
||||
public int fieldLength; /* 16 */
|
||||
public byte[] fieldName = new byte[11]; /* 0-10*/
|
||||
public byte indexFieldFlag; /* 31 */
|
||||
|
||||
/* other class variables */
|
||||
public int nameNullIndex = 0;
|
||||
public int reserv1; /* 12-15 */
|
||||
public short reserv2; /* 18-19 */
|
||||
public short reserv3; /* 21-22 */
|
||||
public byte[] reserv4 = new byte[7]; /* 24-30 */
|
||||
public byte setFieldsFlag; /* 23 */
|
||||
public byte workAreaId; /* 20 */
|
||||
|
||||
public DBFField()
|
||||
{
|
||||
}
|
||||
|
||||
public DBFField(string fieldName, NativeDbType type)
|
||||
{
|
||||
Name = fieldName;
|
||||
DataType = type;
|
||||
}
|
||||
|
||||
public DBFField(string fieldName,
|
||||
NativeDbType type,
|
||||
int fieldLength)
|
||||
{
|
||||
Name = fieldName;
|
||||
DataType = type;
|
||||
FieldLength = fieldLength;
|
||||
}
|
||||
|
||||
public DBFField(string fieldName,
|
||||
NativeDbType type,
|
||||
int fieldLength,
|
||||
int decimalCount)
|
||||
{
|
||||
Name = fieldName;
|
||||
DataType = type;
|
||||
FieldLength = fieldLength;
|
||||
DecimalCount = decimalCount;
|
||||
}
|
||||
|
||||
public int Size => SIZE;
|
||||
|
||||
/**
|
||||
Returns the name of the field.
|
||||
|
||||
@return Name of the field as String.
|
||||
*/
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => Encoding.ASCII.GetString(fieldName, 0, nameNullIndex);
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentException("Field name cannot be null");
|
||||
}
|
||||
|
||||
if (value.Length == 0
|
||||
|| value.Length > 10)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Field name should be of length 0-10");
|
||||
}
|
||||
|
||||
fieldName = Encoding.ASCII.GetBytes(value);
|
||||
nameNullIndex = fieldName.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the data type of the field.
|
||||
|
||||
@return Data type as byte.
|
||||
*/
|
||||
|
||||
public Type Type => Utils.TypeForNativeDBType(DataType);
|
||||
|
||||
|
||||
public NativeDbType DataType
|
||||
{
|
||||
get => (NativeDbType)dataType;
|
||||
set
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case NativeDbType.Date:
|
||||
fieldLength = 8; /* fall through */
|
||||
goto default;
|
||||
case NativeDbType.Memo:
|
||||
fieldLength = 10;
|
||||
goto default;
|
||||
case NativeDbType.Logical:
|
||||
fieldLength = 1;
|
||||
goto default;
|
||||
default:
|
||||
dataType = (byte)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns field length.
|
||||
|
||||
@return field length as int.
|
||||
*/
|
||||
|
||||
public int FieldLength
|
||||
{
|
||||
get
|
||||
{
|
||||
if (DataType == NativeDbType.Char)
|
||||
{
|
||||
return fieldLength + (decimalCount * 256);
|
||||
}
|
||||
|
||||
return fieldLength;
|
||||
}
|
||||
/**
|
||||
Length of the field.
|
||||
This method should be called before calling setDecimalCount().
|
||||
|
||||
@param Length of the field as int.
|
||||
*/
|
||||
set
|
||||
{
|
||||
if (value <= 0)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Field length should be a positive number");
|
||||
}
|
||||
|
||||
switch (DataType)
|
||||
{
|
||||
case NativeDbType.Date:
|
||||
case NativeDbType.Memo:
|
||||
case NativeDbType.Logical:
|
||||
throw new NotSupportedException(
|
||||
"Cannot set length on this type of field");
|
||||
case NativeDbType.Char when value > 255:
|
||||
fieldLength = value % 256;
|
||||
decimalCount = (byte) (value / 256);
|
||||
return;
|
||||
default:
|
||||
fieldLength = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the decimal part. This is applicable
|
||||
only if the field type if of numeric in nature.
|
||||
|
||||
If the field is specified to hold integral values
|
||||
the value returned by this method will be zero.
|
||||
|
||||
@return decimal field size as int.
|
||||
*/
|
||||
|
||||
public int DecimalCount
|
||||
{
|
||||
get => decimalCount;
|
||||
/**
|
||||
Sets the decimal place size of the field.
|
||||
Before calling this method the size of the field
|
||||
should be set by calling setFieldLength().
|
||||
|
||||
@param Size of the decimal field.
|
||||
*/
|
||||
set
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Decimal length should be a positive number");
|
||||
}
|
||||
|
||||
if (value > fieldLength)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Decimal length should be less than field length");
|
||||
}
|
||||
|
||||
decimalCount = (byte) value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Read(BinaryReader reader)
|
||||
{
|
||||
var t_byte = reader.ReadByte(); /* 0 */
|
||||
if (t_byte == DBFFieldType.EndOfField)
|
||||
{
|
||||
//System.out.println( "End of header found");
|
||||
return false;
|
||||
}
|
||||
|
||||
reader.Read(fieldName, 1, 10); /* 1-10 */
|
||||
fieldName[0] = t_byte;
|
||||
|
||||
for (var i = 0; i < fieldName.Length; i++)
|
||||
{
|
||||
if (fieldName[i]
|
||||
== 0)
|
||||
{
|
||||
nameNullIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dataType = reader.ReadByte(); /* 11 */
|
||||
reserv1 = reader.ReadInt32(); /* 12-15 */
|
||||
fieldLength = reader.ReadByte(); /* 16 */
|
||||
decimalCount = reader.ReadByte(); /* 17 */
|
||||
reserv2 = reader.ReadInt16(); /* 18-19 */
|
||||
workAreaId = reader.ReadByte(); /* 20 */
|
||||
reserv3 = reader.ReadInt16(); /* 21-22 */
|
||||
setFieldsFlag = reader.ReadByte(); /* 23 */
|
||||
reader.Read(reserv4, 0, 7); /* 24-30 */
|
||||
indexFieldFlag = reader.ReadByte(); /* 31 */
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Writes the content of DBFField object into the stream as per
|
||||
DBF format specifications.
|
||||
|
||||
@param os OutputStream
|
||||
@throws IOException if any stream related issues occur.
|
||||
*/
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
// Field Name
|
||||
writer.Write(fieldName); /* 0-10 */
|
||||
writer.Write(new byte[11 - fieldName.Length],
|
||||
0,
|
||||
11 - fieldName.Length);
|
||||
|
||||
// data type
|
||||
writer.Write(dataType); /* 11 */
|
||||
writer.Write(reserv1); /* 12-15 */
|
||||
writer.Write((byte) fieldLength); /* 16 */
|
||||
writer.Write(decimalCount); /* 17 */
|
||||
writer.Write(reserv2); /* 18-19 */
|
||||
writer.Write(workAreaId); /* 20 */
|
||||
writer.Write(reserv3); /* 21-22 */
|
||||
writer.Write(setFieldsFlag); /* 23 */
|
||||
writer.Write(reserv4); /* 24-30*/
|
||||
writer.Write(indexFieldFlag); /* 31 */
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a DBFField object from the data read from the given DataInputStream.
|
||||
|
||||
The data in the DataInputStream object is supposed to be organised correctly
|
||||
and the stream "pointer" is supposed to be positioned properly.
|
||||
|
||||
@param in DataInputStream
|
||||
@return Returns the created DBFField object.
|
||||
@throws IOException If any stream reading problems occurs.
|
||||
*/
|
||||
|
||||
internal static DBFField CreateField(BinaryReader reader)
|
||||
{
|
||||
var field = new DBFField();
|
||||
if (field.Read(reader))
|
||||
{
|
||||
return field;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
86
dotnetdbf/DBFFieldType.cs
Normal file
86
dotnetdbf/DBFFieldType.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
DBFFieldType
|
||||
Class for reading the records assuming that the given
|
||||
InputStream comtains DBF data.
|
||||
|
||||
This file is part of DotNetDBF packege.
|
||||
|
||||
author (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
|
||||
License: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
*/
|
||||
|
||||
using System.Data;
|
||||
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public enum NativeDbType : byte
|
||||
{
|
||||
Autoincrement = (byte) 0x2B, //+ in ASCII
|
||||
Timestamp = (byte) 0x40, //@ in ASCII
|
||||
Binary = (byte) 0x42, //B in ASCII
|
||||
Char = (byte) 0x43, //C in ASCII
|
||||
Date = (byte) 0x44, //D in ASCII
|
||||
Float = (byte) 0x46, //F in ASCII
|
||||
Ole = (byte) 0x47, //G in ASCII
|
||||
Long = (byte) 0x49, //I in ASCII
|
||||
Logical = (byte) 0x4C, //L in ASCII
|
||||
Memo = (byte) 0x4D, //M in ASCII
|
||||
Numeric = (byte) 0x4E, //N in ASCII
|
||||
Double = (byte) 0x4F, //O in ASCII
|
||||
}
|
||||
|
||||
public static class DBFFieldType
|
||||
{
|
||||
public const byte EndOfData = 0x1A; //^Z End of File
|
||||
public const byte EndOfField = 0x0D; //End of Field
|
||||
public const byte False = 0x46; //F in Ascii
|
||||
public const byte Space = 0x20; //Space in ascii
|
||||
public const byte True = 0x54; //T in ascii
|
||||
public const byte UnknownByte = 0x3F; //Unknown Bool value
|
||||
public const string Unknown = "?"; //Unknown value
|
||||
|
||||
public static DbType FromNative(NativeDbType @byte)
|
||||
{
|
||||
switch (@byte)
|
||||
{
|
||||
case NativeDbType.Char:
|
||||
return DbType.AnsiStringFixedLength;
|
||||
case NativeDbType.Logical:
|
||||
return DbType.Boolean;
|
||||
case NativeDbType.Numeric:
|
||||
return DbType.Decimal;
|
||||
case NativeDbType.Date:
|
||||
return DbType.Date;
|
||||
case NativeDbType.Float:
|
||||
return DbType.Decimal;
|
||||
case NativeDbType.Memo:
|
||||
return DbType.AnsiString;
|
||||
default:
|
||||
return DbType.Object;
|
||||
}
|
||||
}
|
||||
|
||||
public static NativeDbType FromDbType(DbType dbType)
|
||||
{
|
||||
switch (dbType)
|
||||
{
|
||||
case DbType.AnsiStringFixedLength:
|
||||
return NativeDbType.Char;
|
||||
case DbType.Boolean:
|
||||
return NativeDbType.Logical;
|
||||
case DbType.Decimal:
|
||||
return NativeDbType.Numeric;
|
||||
case DbType.Date:
|
||||
return NativeDbType.Date;
|
||||
case DbType.AnsiString:
|
||||
return NativeDbType.Memo;
|
||||
default:
|
||||
throw new DBFException(
|
||||
$"Unsupported Type {dbType}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
182
dotnetdbf/DBFHeader.cs
Normal file
182
dotnetdbf/DBFHeader.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
DBFHeader
|
||||
Class for reading the metadata assuming that the given
|
||||
InputStream carries DBF data.
|
||||
|
||||
This file is part of DotNetDBF packege.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
|
||||
License: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
[Obsolete("Use DBFSignature instead", error:true)]
|
||||
public static class DBFSigniture
|
||||
{
|
||||
public const byte NotSet = 0,
|
||||
WithMemo = 0x80,
|
||||
DBase3 = 0x03,
|
||||
DBase3WithMemo = DBase3 | WithMemo;
|
||||
}
|
||||
|
||||
public static class DBFSignature
|
||||
{
|
||||
public const byte NotSet = 0,
|
||||
WithMemo = 0x80,
|
||||
DBase3 = 0x03,
|
||||
DBase3WithMemo = DBase3 | WithMemo;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum MemoFlags : byte
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public class DBFHeader
|
||||
{
|
||||
public const byte HeaderRecordTerminator = 0x0D;
|
||||
|
||||
internal byte Signature { get; set; } /* 0 */
|
||||
internal byte Year { set; get; } /* 1 */
|
||||
internal byte Month { set; get; } /* 2 */
|
||||
internal byte Day { set; get; } /* 3 */
|
||||
internal int NumberOfRecords { set; get; } /* 4-7 */
|
||||
internal short HeaderLength { set; get; } /* 8-9 */
|
||||
internal short RecordLength { set; get; } /* 10-11 */
|
||||
private short _reserv1; /* 12-13 */
|
||||
private byte _incompleteTransaction; /* 14 */
|
||||
private byte _encryptionFlag; /* 15 */
|
||||
private int _freeRecordThread; /* 16-19 */
|
||||
private int _reserv2; /* 20-23 */
|
||||
private int _reserv3; /* 24-27 */
|
||||
private byte _mdxFlag; /* 28 */
|
||||
internal byte LanguageDriver { get; set; } /* 29 */
|
||||
private short _reserv4; /* 30-31 */
|
||||
internal DBFField[] FieldArray { set; get; } /* each 32 bytes */
|
||||
|
||||
|
||||
public DBFHeader()
|
||||
{
|
||||
Signature = DBFSignature.DBase3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal short Size => (short) (sizeof(byte) +
|
||||
sizeof(byte) + sizeof(byte) + sizeof(byte) +
|
||||
sizeof(int) +
|
||||
sizeof(short) +
|
||||
sizeof(short) +
|
||||
sizeof(short) +
|
||||
sizeof(byte) +
|
||||
sizeof(byte) +
|
||||
sizeof(int) +
|
||||
sizeof(int) +
|
||||
sizeof(int) +
|
||||
sizeof(byte) +
|
||||
sizeof(byte) +
|
||||
sizeof(short) +
|
||||
(DBFField.SIZE * FieldArray.Length) +
|
||||
sizeof(byte));
|
||||
|
||||
internal short RecordSize
|
||||
{
|
||||
get
|
||||
{
|
||||
var tRecordLength = 0;
|
||||
for (var i = 0; i < FieldArray.Length; i++)
|
||||
{
|
||||
tRecordLength += FieldArray[i].FieldLength;
|
||||
}
|
||||
|
||||
return (short) (tRecordLength + 1);
|
||||
}
|
||||
}
|
||||
|
||||
internal void Read(BinaryReader dataInput)
|
||||
{
|
||||
Signature = dataInput.ReadByte(); /* 0 */
|
||||
Year = dataInput.ReadByte(); /* 1 */
|
||||
Month = dataInput.ReadByte(); /* 2 */
|
||||
Day = dataInput.ReadByte(); /* 3 */
|
||||
NumberOfRecords = dataInput.ReadInt32(); /* 4-7 */
|
||||
|
||||
HeaderLength = dataInput.ReadInt16(); /* 8-9 */
|
||||
RecordLength = dataInput.ReadInt16(); /* 10-11 */
|
||||
|
||||
_reserv1 = dataInput.ReadInt16(); /* 12-13 */
|
||||
_incompleteTransaction = dataInput.ReadByte(); /* 14 */
|
||||
_encryptionFlag = dataInput.ReadByte(); /* 15 */
|
||||
_freeRecordThread = dataInput.ReadInt32(); /* 16-19 */
|
||||
_reserv2 = dataInput.ReadInt32(); /* 20-23 */
|
||||
_reserv3 = dataInput.ReadInt32(); /* 24-27 */
|
||||
_mdxFlag = dataInput.ReadByte(); /* 28 */
|
||||
LanguageDriver = dataInput.ReadByte(); /* 29 */
|
||||
_reserv4 = dataInput.ReadInt16(); /* 30-31 */
|
||||
|
||||
|
||||
var v_fields = new List<DBFField>();
|
||||
|
||||
var field = DBFField.CreateField(dataInput); /* 32 each */
|
||||
while (field != null)
|
||||
{
|
||||
v_fields.Add(field);
|
||||
field = DBFField.CreateField(dataInput);
|
||||
}
|
||||
|
||||
FieldArray = v_fields.ToArray();
|
||||
//System.out.println( "Number of fields: " + _fieldArray.length);
|
||||
}
|
||||
|
||||
internal void Write(BinaryWriter dataOutput)
|
||||
{
|
||||
dataOutput.Write(Signature); /* 0 */
|
||||
var tNow = DateTime.Now;
|
||||
Year = (byte) (tNow.Year - 1900);
|
||||
Month = (byte) (tNow.Month);
|
||||
Day = (byte) (tNow.Day);
|
||||
|
||||
dataOutput.Write(Year); /* 1 */
|
||||
dataOutput.Write(Month); /* 2 */
|
||||
dataOutput.Write(Day); /* 3 */
|
||||
|
||||
//System.out.println( "Number of records in O/S: " + numberOfRecords);
|
||||
dataOutput.Write(NumberOfRecords); /* 4-7 */
|
||||
|
||||
HeaderLength = Size;
|
||||
dataOutput.Write(HeaderLength); /* 8-9 */
|
||||
|
||||
RecordLength = RecordSize;
|
||||
dataOutput.Write(RecordLength); /* 10-11 */
|
||||
|
||||
dataOutput.Write(_reserv1); /* 12-13 */
|
||||
dataOutput.Write(_incompleteTransaction); /* 14 */
|
||||
dataOutput.Write(_encryptionFlag); /* 15 */
|
||||
dataOutput.Write(_freeRecordThread); /* 16-19 */
|
||||
dataOutput.Write(_reserv2); /* 20-23 */
|
||||
dataOutput.Write(_reserv3); /* 24-27 */
|
||||
|
||||
dataOutput.Write(_mdxFlag); /* 28 */
|
||||
dataOutput.Write(LanguageDriver); /* 29 */
|
||||
dataOutput.Write(_reserv4); /* 30-31 */
|
||||
|
||||
foreach (var field in FieldArray)
|
||||
{
|
||||
field.Write(dataOutput);
|
||||
}
|
||||
|
||||
dataOutput.Write(HeaderRecordTerminator); /* n+1 */
|
||||
}
|
||||
}
|
||||
}
|
||||
487
dotnetdbf/DBFReader.cs
Normal file
487
dotnetdbf/DBFReader.cs
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
DBFReader
|
||||
Class for reading the records assuming that the given
|
||||
InputStream contains DBF data.
|
||||
|
||||
This file is part of DotNetDBF package.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
|
||||
License: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public class DBFReader : DBFBase, IDisposable
|
||||
{
|
||||
private BinaryReader _dataInputStream;
|
||||
private DBFHeader _header;
|
||||
private Stream _dataMemo;
|
||||
|
||||
private string _dataMemoLoc;
|
||||
|
||||
private int[] _selectFields = new int[] {};
|
||||
private int[] _orderedSelectFields = new int[] {};
|
||||
/* Class specific variables */
|
||||
private bool _isClosed = true;
|
||||
|
||||
|
||||
/**
|
||||
Initializes a DBFReader object.
|
||||
|
||||
When this constructor returns the object
|
||||
will have completed reading the header (meta date) and
|
||||
header information can be queried there on. And it will
|
||||
be ready to return the first row.
|
||||
|
||||
@param InputStream where the data is read from.
|
||||
*/
|
||||
|
||||
|
||||
public void SetSelectFields(params string[] aParams)
|
||||
{
|
||||
_selectFields =
|
||||
aParams.Select(
|
||||
it =>
|
||||
Array.FindIndex(_header.FieldArray,
|
||||
jt => jt.Name.Equals(it, StringComparison.OrdinalIgnoreCase))).ToArray();
|
||||
_orderedSelectFields = _selectFields.OrderBy(it => it).ToArray();
|
||||
}
|
||||
|
||||
public DBFField[] GetSelectFields()
|
||||
{
|
||||
return _selectFields.Any()
|
||||
? _selectFields.Select(it => _header.FieldArray[it]).ToArray()
|
||||
: _header.FieldArray;
|
||||
}
|
||||
|
||||
|
||||
public DBFReader(string anIn)
|
||||
{
|
||||
try
|
||||
{
|
||||
_dataInputStream = new BinaryReader(
|
||||
File.Open(anIn,
|
||||
FileMode.Open,
|
||||
FileAccess.Read,
|
||||
FileShare.Read)
|
||||
);
|
||||
|
||||
var dbtPath = Path.ChangeExtension(anIn, "dbt");
|
||||
if (File.Exists(dbtPath))
|
||||
{
|
||||
_dataMemoLoc = dbtPath;
|
||||
}
|
||||
|
||||
_isClosed = false;
|
||||
_header = new DBFHeader();
|
||||
_header.Read(_dataInputStream);
|
||||
|
||||
/* it might be required to leap to the start of records at times */
|
||||
var t_dataStartIndex = _header.HeaderLength
|
||||
- (32 + (32 * _header.FieldArray.Length))
|
||||
- 1;
|
||||
if (t_dataStartIndex > 0)
|
||||
{
|
||||
_dataInputStream.ReadBytes((t_dataStartIndex));
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new DBFException("Failed To Read DBF", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public DBFReader(Stream anIn)
|
||||
{
|
||||
try
|
||||
{
|
||||
_dataInputStream = new BinaryReader(anIn);
|
||||
_isClosed = false;
|
||||
_header = new DBFHeader();
|
||||
_header.Read(_dataInputStream);
|
||||
|
||||
/* it might be required to leap to the start of records at times */
|
||||
var t_dataStartIndex = _header.HeaderLength
|
||||
- (32 + (32 * _header.FieldArray.Length))
|
||||
- 1;
|
||||
if (t_dataStartIndex > 0)
|
||||
{
|
||||
_dataInputStream.ReadBytes((t_dataStartIndex));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DBFException("Failed To Read DBF", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of records in the DBF.
|
||||
*/
|
||||
|
||||
public int RecordCount => _header.NumberOfRecords;
|
||||
|
||||
/**
|
||||
Returns the asked Field. In case of an invalid index,
|
||||
it returns a ArrayIndexOutOfBoundsException.
|
||||
|
||||
@param index. Index of the field. Index of the first field is zero.
|
||||
*/
|
||||
|
||||
public DBFField[] Fields => _header.FieldArray;
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing, releasing,
|
||||
/// or resetting unmanaged resources.</summary>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public void Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public string DataMemoLoc
|
||||
{
|
||||
get => _dataMemoLoc;
|
||||
set => _dataMemoLoc = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public delegate Stream LazyStream();
|
||||
|
||||
private Stream _loadedStream;
|
||||
|
||||
private LazyStream GetLazyStreamFromLocation()
|
||||
{
|
||||
|
||||
if (_dataMemo == null && !string.IsNullOrEmpty(_dataMemoLoc))
|
||||
{
|
||||
return () => _loadedStream ??
|
||||
(_loadedStream = File.Open(_dataMemoLoc, FileMode.Open, FileAccess.Read,
|
||||
FileShare.Read));
|
||||
}
|
||||
if (_dataMemo != null)
|
||||
{
|
||||
return () => _dataMemo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Stream DataMemo
|
||||
{
|
||||
get => _dataMemo;
|
||||
set => _dataMemo = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb =
|
||||
new StringBuilder(_header.Year + "/" + _header.Month + "/"
|
||||
+ _header.Day + "\n"
|
||||
+ "Total records: " + _header.NumberOfRecords +
|
||||
"\nHeader length: " + _header.HeaderLength +
|
||||
"");
|
||||
|
||||
for (var i = 0; i < _header.FieldArray.Length; i++)
|
||||
{
|
||||
sb.Append(_header.FieldArray[i].Name);
|
||||
sb.Append("\n");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
|
||||
|
||||
_loadedStream?.Close();
|
||||
_dataMemo?.Close();
|
||||
_dataInputStream.Close();
|
||||
|
||||
_dataMemo?.Dispose();
|
||||
|
||||
|
||||
|
||||
_isClosed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
Reads the returns the next row in the DBF stream.
|
||||
@returns The next row as an Object array. Types of the elements
|
||||
these arrays follow the convention mentioned in the class description.
|
||||
*/
|
||||
|
||||
public object[] NextRecord(bool throwOnParsingError = true)
|
||||
{
|
||||
return NextRecord(_selectFields, _orderedSelectFields, throwOnParsingError);
|
||||
}
|
||||
|
||||
internal object[] NextRecord(IEnumerable<int> selectIndexes, IList<int> sortedIndexes, bool throwOnParsingError = true)
|
||||
{
|
||||
if (_isClosed)
|
||||
{
|
||||
throw new DBFException("Source is not open");
|
||||
}
|
||||
var tOrderdSelectIndexes = sortedIndexes;
|
||||
|
||||
var recordObjects = new object[_header.FieldArray.Length];
|
||||
|
||||
try
|
||||
{
|
||||
var isDeleted = false;
|
||||
do
|
||||
{
|
||||
if (isDeleted)
|
||||
{
|
||||
_dataInputStream.ReadBytes(_header.RecordLength - 1);
|
||||
}
|
||||
|
||||
int t_byte = _dataInputStream.ReadByte();
|
||||
if (t_byte == DBFFieldType.EndOfData)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
isDeleted = (t_byte == '*');
|
||||
} while (isDeleted);
|
||||
|
||||
var j = 0;
|
||||
var k = -1;
|
||||
for (var i = 0; i < _header.FieldArray.Length; i++)
|
||||
{
|
||||
if (tOrderdSelectIndexes.Count == j && j != 0
|
||||
||
|
||||
(tOrderdSelectIndexes.Count > j && tOrderdSelectIndexes[j] > i && tOrderdSelectIndexes[j] != k))
|
||||
{
|
||||
_dataInputStream.BaseStream.Seek(_header.FieldArray[i].FieldLength, SeekOrigin.Current);
|
||||
continue;
|
||||
}
|
||||
if (tOrderdSelectIndexes.Count > j)
|
||||
k = tOrderdSelectIndexes[j];
|
||||
j++;
|
||||
|
||||
|
||||
switch (_header.FieldArray[i].DataType)
|
||||
{
|
||||
case NativeDbType.Char:
|
||||
|
||||
var b_array = new byte[
|
||||
_header.FieldArray[i].FieldLength
|
||||
];
|
||||
_dataInputStream.Read(b_array, 0, b_array.Length);
|
||||
|
||||
recordObjects[i] = CharEncoding.GetString(b_array).TrimEnd();
|
||||
break;
|
||||
|
||||
case NativeDbType.Date:
|
||||
|
||||
var t_byte_year = new byte[4];
|
||||
_dataInputStream.Read(t_byte_year,
|
||||
0,
|
||||
t_byte_year.Length);
|
||||
|
||||
var t_byte_month = new byte[2];
|
||||
_dataInputStream.Read(t_byte_month,
|
||||
0,
|
||||
t_byte_month.Length);
|
||||
|
||||
var t_byte_day = new byte[2];
|
||||
_dataInputStream.Read(t_byte_day,
|
||||
0,
|
||||
t_byte_day.Length);
|
||||
|
||||
try
|
||||
{
|
||||
var tYear = CharEncoding.GetString(t_byte_year);
|
||||
var tMonth = CharEncoding.GetString(t_byte_month);
|
||||
var tDay = CharEncoding.GetString(t_byte_day);
|
||||
|
||||
if (int.TryParse(tYear, out var tIntYear) &&
|
||||
int.TryParse(tMonth, out var tIntMonth) &&
|
||||
int.TryParse(tDay, out var tIntDay))
|
||||
{
|
||||
recordObjects[i] = new DateTime(
|
||||
tIntYear,
|
||||
tIntMonth,
|
||||
tIntDay);
|
||||
}
|
||||
else
|
||||
{
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
/* this field may be empty or may have improper value set */
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Float:
|
||||
|
||||
try
|
||||
{
|
||||
var t_float = new byte[
|
||||
_header.FieldArray[i].FieldLength
|
||||
];
|
||||
_dataInputStream.Read(t_float, 0, t_float.Length);
|
||||
var tParsed = CharEncoding.GetString(t_float);
|
||||
var tLast = tParsed.Substring(tParsed.Length - 1);
|
||||
if (tParsed.Length > 0
|
||||
&& tLast != " "
|
||||
&& tLast != NullSymbol)
|
||||
{
|
||||
//
|
||||
// A Float in FoxPro has 20 significant digits, since it is
|
||||
// stored as a string with possible E-postfix notation.
|
||||
// An IEEE 754 float or double can not handle this number of digits
|
||||
// correctly. Therefor the only correct implementation is to use a decimal.
|
||||
//
|
||||
recordObjects[i] = decimal.Parse(tParsed,
|
||||
NumberStyles.Float | NumberStyles.AllowLeadingWhite,
|
||||
NumberFormatInfo.InvariantInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
}
|
||||
catch (FormatException e)
|
||||
{
|
||||
if (throwOnParsingError)
|
||||
throw new DBFException("Failed to parse Float", e);
|
||||
|
||||
recordObjects[i] = default(decimal);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Numeric:
|
||||
|
||||
try
|
||||
{
|
||||
var t_numeric = new byte[
|
||||
_header.FieldArray[i].FieldLength
|
||||
];
|
||||
_dataInputStream.Read(t_numeric,
|
||||
0,
|
||||
t_numeric.Length);
|
||||
var tParsed =
|
||||
CharEncoding.GetString(t_numeric);
|
||||
var tLast = tParsed.Substring(tParsed.Length - 1);
|
||||
if (tParsed.Length > 0
|
||||
&& tLast != " "
|
||||
&& tLast != NullSymbol)
|
||||
{
|
||||
recordObjects[i] = decimal.Parse(tParsed,
|
||||
NumberStyles.Float | NumberStyles.AllowLeadingWhite,
|
||||
NumberFormatInfo.InvariantInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
}
|
||||
catch (FormatException e)
|
||||
{
|
||||
if (throwOnParsingError)
|
||||
throw new DBFException(
|
||||
"Failed to parse Number", e);
|
||||
|
||||
recordObjects[i] = default(decimal);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Logical:
|
||||
|
||||
var t_logical = _dataInputStream.ReadByte();
|
||||
//todo find out whats really valid
|
||||
if (t_logical == 'Y' || t_logical == 't'
|
||||
|| t_logical == 'T'
|
||||
|| t_logical == 't')
|
||||
{
|
||||
recordObjects[i] = true;
|
||||
}
|
||||
else if (t_logical == DBFFieldType.UnknownByte)
|
||||
{
|
||||
recordObjects[i] = DBNull.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
recordObjects[i] = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case NativeDbType.Memo:
|
||||
if (
|
||||
|
||||
string.IsNullOrEmpty(_dataMemoLoc) &&
|
||||
|
||||
_dataMemo is null)
|
||||
{
|
||||
throw new Exception("Memo Location Not Set");
|
||||
}
|
||||
|
||||
|
||||
var rawMemoPointer = _dataInputStream.ReadBytes(_header.FieldArray[i].FieldLength);
|
||||
var memoPointer = CharEncoding.GetString(rawMemoPointer);
|
||||
if (string.IsNullOrEmpty(memoPointer))
|
||||
{
|
||||
recordObjects[i] = DBNull.Value;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!long.TryParse(memoPointer, out var tBlock))
|
||||
{
|
||||
//Because Memo files can vary and are often the least important data,
|
||||
//we will return null when it doesn't match our format.
|
||||
recordObjects[i] = DBNull.Value;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
recordObjects[i] = new MemoValue(tBlock, this,
|
||||
_dataMemoLoc,
|
||||
GetLazyStreamFromLocation());
|
||||
break;
|
||||
default:
|
||||
{
|
||||
byte[] data = _dataInputStream.ReadBytes(_header.FieldArray[i].FieldLength);
|
||||
|
||||
recordObjects[i] = data != null ? (object)data : DBNull.Value;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (EndOfStreamException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DBFException("Problem Reading File", e);
|
||||
}
|
||||
|
||||
return selectIndexes.Any() ? selectIndexes.Select(it => recordObjects[it]).ToArray() : recordObjects;
|
||||
}
|
||||
}
|
||||
}
|
||||
528
dotnetdbf/DBFWriter.cs
Normal file
528
dotnetdbf/DBFWriter.cs
Normal file
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
DBFWriter
|
||||
Class for defining a DBF structure and addin data to that structure and
|
||||
finally writing it to an OutputStream.
|
||||
|
||||
This file is part of DotNetDBF packege.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public class DBFWriter : DBFBase, IDisposable
|
||||
{
|
||||
private DBFHeader header;
|
||||
private Stream raf;
|
||||
private int recordCount;
|
||||
private List<object> v_records = new List<object>();
|
||||
private Stream _dataMemo;
|
||||
|
||||
private string _dataMemoLoc;
|
||||
|
||||
/// Creates an empty Object.
|
||||
public DBFWriter()
|
||||
{
|
||||
header = new DBFHeader();
|
||||
}
|
||||
|
||||
|
||||
/// Creates a DBFWriter which can append to records to an existing DBF file.
|
||||
/// @param dbfFile. The file passed in should be a valid DBF file.
|
||||
/// @exception Throws DBFException if the passed in file does exist but not a valid DBF file, or if an IO error occurs.
|
||||
public DBFWriter(string dbfFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
raf =
|
||||
File.Open(dbfFile,
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite);
|
||||
|
||||
DataMemoLoc = Path.ChangeExtension(dbfFile, "dbt");
|
||||
|
||||
/* before proceeding check whether the passed in File object
|
||||
is an empty/non-existent file or not.
|
||||
*/
|
||||
if (raf.Length == 0)
|
||||
{
|
||||
header = new DBFHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
header = new DBFHeader();
|
||||
header.Read(new BinaryReader(raf));
|
||||
|
||||
/* position file pointer at the end of the raf */
|
||||
raf.Seek(-1, SeekOrigin.End);
|
||||
/* check whether the last byte is 0x1A (end of file marker for dbf files) - in this case move 1 byte back to ignore it when writing new records */
|
||||
var lastByte = raf.ReadByte(); /* Advances to end of stream */
|
||||
if (lastByte == DBFFieldType.EndOfData)
|
||||
{
|
||||
raf.Seek(-1, SeekOrigin.End);
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
throw new DBFException("Specified file is not found. ", e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DBFException(" while reading header", e);
|
||||
}
|
||||
recordCount = header.NumberOfRecords;
|
||||
}
|
||||
|
||||
public DBFWriter(Stream dbfFile)
|
||||
{
|
||||
raf = dbfFile;
|
||||
|
||||
/* before proceeding check whether the passed in File object
|
||||
is an empty/non-existent file or not.
|
||||
*/
|
||||
if (raf.Length == 0)
|
||||
{
|
||||
header = new DBFHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
header = new DBFHeader();
|
||||
header.Read(new BinaryReader(raf));
|
||||
|
||||
/* position file pointer at the end of the raf */
|
||||
raf.Seek(-1, SeekOrigin.End);
|
||||
/* check whether the last byte is 0x1A (end of file marker for dbf files) - in this case move 1 byte back to ignore it when writing new records */
|
||||
var lastByte = raf.ReadByte(); /* Advances to end of stream */
|
||||
if (lastByte == DBFFieldType.EndOfData)
|
||||
{
|
||||
raf.Seek(-1, SeekOrigin.End);
|
||||
}
|
||||
|
||||
recordCount = header.NumberOfRecords;
|
||||
}
|
||||
|
||||
public byte Signature
|
||||
{
|
||||
get => header.Signature;
|
||||
set => header.Signature = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public string DataMemoLoc
|
||||
{
|
||||
get => _dataMemoLoc;
|
||||
set
|
||||
{
|
||||
_dataMemoLoc = value;
|
||||
|
||||
_dataMemo?.Close();
|
||||
_dataMemo = File.Open(_dataMemoLoc,
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream DataMemo
|
||||
{
|
||||
get => _dataMemo;
|
||||
set => _dataMemo = value;
|
||||
}
|
||||
|
||||
public byte LanguageDriver
|
||||
{
|
||||
set
|
||||
{
|
||||
if (header.LanguageDriver != 0x00)
|
||||
{
|
||||
throw new DBFException("LanguageDriver has already been set");
|
||||
}
|
||||
|
||||
header.LanguageDriver = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public DBFField[] Fields
|
||||
{
|
||||
get => header.FieldArray;
|
||||
|
||||
|
||||
set
|
||||
{
|
||||
if (header.FieldArray != null)
|
||||
{
|
||||
throw new DBFException("Fields has already been set");
|
||||
}
|
||||
|
||||
if (value == null
|
||||
|| value.Length == 0)
|
||||
{
|
||||
throw new DBFException("Should have at least one field");
|
||||
}
|
||||
|
||||
for (var i = 0; i < value.Length; i++)
|
||||
{
|
||||
if (value[i] == null)
|
||||
{
|
||||
throw new DBFException("Field " + (i + 1) + " is null");
|
||||
}
|
||||
}
|
||||
|
||||
header.FieldArray = value;
|
||||
|
||||
try
|
||||
{
|
||||
if (raf != null
|
||||
&& raf.Length == 0)
|
||||
{
|
||||
/*
|
||||
this is a new/non-existent file. So write header before proceeding
|
||||
*/
|
||||
header.Write(new BinaryWriter(raf));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DBFException("Error accessing file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing, releasing,
|
||||
/// or resetting unmanaged resources.</summary>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public void Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/**
|
||||
Add a record.
|
||||
*/
|
||||
|
||||
public void WriteRecord(params object[] values)
|
||||
{
|
||||
if (raf == null)
|
||||
{
|
||||
throw new DBFException(
|
||||
"Not initialized with file for WriteRecord use, use AddRecord instead");
|
||||
}
|
||||
AddRecord(values, true);
|
||||
}
|
||||
|
||||
public void AddRecord(params object[] values)
|
||||
{
|
||||
if (raf != null)
|
||||
{
|
||||
throw new DBFException(
|
||||
"Appending to a file, requires using WriteRecord instead");
|
||||
}
|
||||
AddRecord(values, false);
|
||||
}
|
||||
|
||||
private void AddRecord(object[] values, bool writeImmediately)
|
||||
{
|
||||
if (header.FieldArray == null)
|
||||
{
|
||||
throw new DBFException(
|
||||
"Fields should be set before adding records");
|
||||
}
|
||||
|
||||
if (values == null)
|
||||
{
|
||||
throw new DBFException("Null cannot be added as row");
|
||||
}
|
||||
|
||||
if (values.Length
|
||||
!= header.FieldArray.Length)
|
||||
{
|
||||
throw new DBFException(
|
||||
"Invalid record. Invalid number of fields in row");
|
||||
}
|
||||
|
||||
for (var i = 0; i < header.FieldArray.Length; i++)
|
||||
{
|
||||
var fld = header.FieldArray[i];
|
||||
var val = values[i];
|
||||
|
||||
if (val is null || val is DBNull)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
void ThrowErrorIfNot<T>()
|
||||
{
|
||||
if (!(val is T))
|
||||
{
|
||||
throw new DBFRecordException($"Invalid value '{val}' for field {i}({fld.Name}{fld.DataType})", 0);
|
||||
}
|
||||
}
|
||||
|
||||
switch (fld.DataType)
|
||||
{
|
||||
case NativeDbType.Char:
|
||||
//ignore all objects have ToString()
|
||||
break;
|
||||
|
||||
case NativeDbType.Logical:
|
||||
ThrowErrorIfNot<bool>();
|
||||
break;
|
||||
|
||||
case NativeDbType.Numeric:
|
||||
ThrowErrorIfNot<IConvertible>();
|
||||
break;
|
||||
|
||||
case NativeDbType.Date:
|
||||
ThrowErrorIfNot<DateTime>();
|
||||
break;
|
||||
|
||||
case NativeDbType.Float:
|
||||
ThrowErrorIfNot<IConvertible>();
|
||||
break;
|
||||
case NativeDbType.Memo:
|
||||
ThrowErrorIfNot<MemoValue>();
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
if (!writeImmediately)
|
||||
{
|
||||
v_records.Add(values);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
WriteRecord(new BinaryWriter(raf), values);
|
||||
recordCount++;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DBFException(
|
||||
"Error occured while writing record. ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Writes the set data to the OutputStream.
|
||||
public void Write(Stream tOut)
|
||||
{
|
||||
try
|
||||
{
|
||||
var outStream = new BinaryWriter(tOut);
|
||||
|
||||
header.NumberOfRecords = v_records.Count;
|
||||
header.Write(outStream);
|
||||
|
||||
/* Now write all the records */
|
||||
var t_recCount = v_records.Count;
|
||||
for (var i = 0; i < t_recCount; i++)
|
||||
{
|
||||
/* iterate through records */
|
||||
|
||||
var t_values = (object[]) v_records[i];
|
||||
|
||||
WriteRecord(outStream, t_values);
|
||||
}
|
||||
|
||||
outStream.Write(DBFFieldType.EndOfData);
|
||||
outStream.Flush();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DBFException("Error Writing", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
/* everything is written already. just update the header for record count and the END_OF_DATA mark */
|
||||
header.NumberOfRecords = recordCount;
|
||||
if (raf != null)
|
||||
{
|
||||
raf.Seek(0, SeekOrigin.Begin);
|
||||
header.Write(new BinaryWriter(raf));
|
||||
raf.Seek(0, SeekOrigin.End);
|
||||
raf.WriteByte(DBFFieldType.EndOfData);
|
||||
|
||||
raf.Close();
|
||||
_dataMemo?.Close();
|
||||
|
||||
} else if (!string.IsNullOrEmpty(DataMemoLoc))
|
||||
{
|
||||
DataMemo.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void WriteRecord(BinaryWriter dataOutput, object[] objectArray)
|
||||
{
|
||||
dataOutput.Write((byte) ' ');
|
||||
for (var j = 0; j < header.FieldArray.Length; j++)
|
||||
{
|
||||
/* iterate through fields */
|
||||
|
||||
switch (header.FieldArray[j].DataType)
|
||||
{
|
||||
case NativeDbType.Char:
|
||||
if (objectArray[j] != null && objectArray[j] != DBNull.Value)
|
||||
{
|
||||
var str_value = objectArray[j].ToString();
|
||||
dataOutput.Write(
|
||||
Utils.textPadding(str_value,
|
||||
CharEncoding,
|
||||
header.FieldArray[j].
|
||||
FieldLength
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(
|
||||
Utils.textPadding("",
|
||||
CharEncoding,
|
||||
header.FieldArray[j].
|
||||
FieldLength
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Date:
|
||||
if (objectArray[j] != null && objectArray[j] != DBNull.Value)
|
||||
{
|
||||
var tDate = (DateTime) objectArray[j];
|
||||
|
||||
dataOutput.Write(
|
||||
CharEncoding.GetBytes(tDate.ToString("yyyyMMdd")));
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(
|
||||
Utils.FillArray(new byte[8], DBFFieldType.Space));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Float:
|
||||
|
||||
if (objectArray[j] != null && objectArray[j] != DBNull.Value)
|
||||
{
|
||||
var tDouble = Convert.ToDecimal(objectArray[j]);
|
||||
dataOutput.Write(
|
||||
Utils.NumericFormating(
|
||||
tDouble,
|
||||
CharEncoding,
|
||||
header.FieldArray[j].FieldLength,
|
||||
header.FieldArray[j].DecimalCount
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(
|
||||
Utils.textPadding(
|
||||
NullSymbol,
|
||||
CharEncoding,
|
||||
header.FieldArray[j].FieldLength,
|
||||
Utils.ALIGN_RIGHT
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Numeric:
|
||||
|
||||
if (objectArray[j] != null && objectArray[j] != DBNull.Value)
|
||||
{
|
||||
var tDecimal = Convert.ToDecimal(objectArray[j]);
|
||||
dataOutput.Write(
|
||||
Utils.NumericFormating(
|
||||
tDecimal,
|
||||
CharEncoding,
|
||||
header.FieldArray[j].FieldLength,
|
||||
header.FieldArray[j].DecimalCount
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(
|
||||
Utils.textPadding(
|
||||
NullSymbol,
|
||||
CharEncoding,
|
||||
header.FieldArray[j].FieldLength,
|
||||
Utils.ALIGN_RIGHT
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
case NativeDbType.Logical:
|
||||
|
||||
if (objectArray[j] != null && objectArray[j] != DBNull.Value)
|
||||
{
|
||||
if ((bool) objectArray[j])
|
||||
{
|
||||
dataOutput.Write(DBFFieldType.True);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(DBFFieldType.False);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(DBFFieldType.UnknownByte);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Memo:
|
||||
if (objectArray[j] != null && objectArray[j] != DBNull.Value)
|
||||
{
|
||||
var tMemoValue = ((MemoValue) objectArray[j]);
|
||||
|
||||
tMemoValue.Write(this);
|
||||
|
||||
dataOutput.Write(Utils.NumericFormating(tMemoValue.Block, CharEncoding, 10, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(
|
||||
Utils.textPadding("",
|
||||
CharEncoding,
|
||||
10
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new DBFException("Unknown field type "
|
||||
+ header.FieldArray[j].DataType);
|
||||
}
|
||||
} /* iterating through the fields */
|
||||
}
|
||||
}
|
||||
}
|
||||
37
dotnetdbf/DBTHeader.cs
Normal file
37
dotnetdbf/DBTHeader.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public class DBTHeader
|
||||
{
|
||||
public const byte FieldTerminator = 0x1A;
|
||||
|
||||
|
||||
private int _nextBlock; /* 0-3*/
|
||||
private byte _version = 0x03;
|
||||
|
||||
|
||||
internal int NextBlock
|
||||
{
|
||||
get => _nextBlock;
|
||||
set => _nextBlock = value;
|
||||
}
|
||||
|
||||
internal byte Version
|
||||
{
|
||||
get => _version;
|
||||
set => _version = value;
|
||||
}
|
||||
|
||||
internal void Write(BinaryWriter dataOutput)
|
||||
{
|
||||
dataOutput.Write(_nextBlock);
|
||||
dataOutput.Write(new byte[12]);
|
||||
dataOutput.Write(_version);
|
||||
dataOutput.Write(new byte[495]);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
dotnetdbf/DotNetDBF.csproj
Normal file
33
dotnetdbf/DotNetDBF.csproj
Normal file
@@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net35;netstandard2.0</TargetFrameworks>
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>sn.snk</AssemblyOriginatorKeyFile>
|
||||
<Version>7.0.0.0</Version>
|
||||
<Company>Ekon Benefits</Company>
|
||||
<Copyright>Copyright 2009-2017</Copyright>
|
||||
<Description>This is a basic file parser for reading and writing xBase DBF files particularlly Clipper. Code originally derived from javadbf.</Description>
|
||||
<PackageProjectUrl>https://github.com/ekonbenefits/dotnetdbf</PackageProjectUrl>
|
||||
<PackageTags>clipper xbase dbf</PackageTags>
|
||||
<Authors>Anil Kumar, Jay Tuley</Authors>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<RepositoryUrl>https://github.com/ekonbenefits/dotnetdbf.git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<IncludeSymbols>True</IncludeSymbols>
|
||||
<IncludeSource>True</IncludeSource>
|
||||
<PackageLicenseExpression>LGPL-2.1-or-later</PackageLicenseExpression>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-18618-05" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="original java src\**" />
|
||||
<EmbeddedResource Remove="original java src\**" />
|
||||
<None Remove="original java src\**" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
33
dotnetdbf/DotNetDBF.sln
Normal file
33
dotnetdbf/DotNetDBF.sln
Normal file
@@ -0,0 +1,33 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.9
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetDBF", "DotNetDBF\DotNetDBF.csproj", "{C5E9AE18-1EA3-4C90-AFAB-5323093BE4AC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetDBF.Enumerable", "DotNetDBF.Enumerable\DotNetDBF.Enumerable.csproj", "{3BB97ECD-325D-4288-B355-57CFC1404019}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetDBF.Test", "DotNetDBF.Test\DotNetDBF.Test.csproj", "{8D5436E3-F584-40A0-ACDC-65346ECEADB0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C5E9AE18-1EA3-4C90-AFAB-5323093BE4AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5E9AE18-1EA3-4C90-AFAB-5323093BE4AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5E9AE18-1EA3-4C90-AFAB-5323093BE4AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5E9AE18-1EA3-4C90-AFAB-5323093BE4AC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3BB97ECD-325D-4288-B355-57CFC1404019}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3BB97ECD-325D-4288-B355-57CFC1404019}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3BB97ECD-325D-4288-B355-57CFC1404019}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3BB97ECD-325D-4288-B355-57CFC1404019}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8D5436E3-F584-40A0-ACDC-65346ECEADB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8D5436E3-F584-40A0-ACDC-65346ECEADB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8D5436E3-F584-40A0-ACDC-65346ECEADB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8D5436E3-F584-40A0-ACDC-65346ECEADB0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
9
dotnetdbf/DotNetDBF.sln.DotSettings
Normal file
9
dotnetdbf/DotNetDBF.sln.DotSettings
Normal file
@@ -0,0 +1,9 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DBT/@EntryIndexedValue">DBT</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpNaming/ApplyAutoDetectedRules/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue"><data><IncludeFilters /><ExcludeFilters /></data></s:String>
|
||||
<s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue"><data /></s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=javadbf/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=LGPL/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=reserv/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Tuley/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
164
dotnetdbf/MemoValue.cs
Normal file
164
dotnetdbf/MemoValue.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public class MemoValue
|
||||
{
|
||||
public const string MemoTerminator = "\x1A";
|
||||
private bool _loaded;
|
||||
private bool _new;
|
||||
|
||||
|
||||
public MemoValue(string aValue)
|
||||
{
|
||||
_lockName = $"DotNetDBF.Memo.new.{Guid.NewGuid()}";
|
||||
Value = aValue;
|
||||
}
|
||||
|
||||
|
||||
internal MemoValue(long block, DBFBase aBase,
|
||||
string fileLoc, DBFReader.LazyStream fileStream)
|
||||
{
|
||||
_block = block;
|
||||
_base = aBase;
|
||||
_fileLoc = fileLoc;
|
||||
_fileStream = fileStream;
|
||||
if (string.IsNullOrEmpty(fileLoc))
|
||||
{
|
||||
_lockName = fileStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
_lockName = $"DotNetDBF.Memo.read.{_fileLoc}";
|
||||
}
|
||||
}
|
||||
|
||||
private readonly DBFBase _base;
|
||||
private readonly object _lockName;
|
||||
private long _block;
|
||||
private readonly string _fileLoc;
|
||||
private string _value;
|
||||
private readonly DBFReader.LazyStream _fileStream;
|
||||
|
||||
internal long Block => _block;
|
||||
|
||||
internal void Write(DBFWriter aBase)
|
||||
{
|
||||
lock (_lockName)
|
||||
{
|
||||
if (!_new)
|
||||
return;
|
||||
|
||||
var raf = aBase.DataMemo;
|
||||
|
||||
/* before proceeding check whether the passed in File object
|
||||
is an empty/non-existent file or not.
|
||||
*/
|
||||
if (raf == null)
|
||||
{
|
||||
throw new InvalidDataException("Null Memo Field Stream from Writer");
|
||||
}
|
||||
|
||||
var tWriter = new BinaryWriter(raf, aBase.CharEncoding); //Don't close the stream could be used else where;
|
||||
|
||||
if (raf.Length == 0)
|
||||
{
|
||||
var tHeader = new DBTHeader();
|
||||
tHeader.Write(tWriter);
|
||||
}
|
||||
|
||||
var tValue = _value;
|
||||
if ((tValue.Length + sizeof(int)) % aBase.BlockSize != 0)
|
||||
{
|
||||
tValue = tValue + MemoTerminator;
|
||||
}
|
||||
|
||||
var tPosition = raf.Seek(0, SeekOrigin.End); //Got To End Of File
|
||||
var tBlockDiff = tPosition % aBase.BlockSize;
|
||||
if (tBlockDiff != 0)
|
||||
{
|
||||
tPosition = raf.Seek(aBase.BlockSize - tBlockDiff, SeekOrigin.Current);
|
||||
}
|
||||
_block = tPosition / aBase.BlockSize;
|
||||
var tData = aBase.CharEncoding.GetBytes(tValue);
|
||||
var tDataLength = tData.Length;
|
||||
var tNewDiff = (tDataLength % aBase.BlockSize);
|
||||
tWriter.Write(tData);
|
||||
if (tNewDiff != 0)
|
||||
tWriter.Seek(aBase.BlockSize - (tDataLength % aBase.BlockSize), SeekOrigin.Current);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string Value
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lockName)
|
||||
{
|
||||
if (_new || _loaded) return _value;
|
||||
var fileStream = _fileStream();
|
||||
|
||||
var reader = new BinaryReader(fileStream);
|
||||
|
||||
{
|
||||
reader.BaseStream.Seek(_block * _base.BlockSize, SeekOrigin.Begin);
|
||||
var builder = new StringBuilder();
|
||||
int termIndex;
|
||||
var softReturn = _base.CharEncoding.GetString(new byte[] {0x8d, 0x0a});
|
||||
|
||||
do
|
||||
{
|
||||
var data = reader.ReadBytes(_base.BlockSize);
|
||||
if ((data.Length == 0))
|
||||
{
|
||||
throw new DBTException("Missing Data for block or no 1a memo terminator");
|
||||
}
|
||||
var stringVal = _base.CharEncoding.GetString(data);
|
||||
termIndex = stringVal.IndexOf(MemoTerminator, StringComparison.Ordinal);
|
||||
if (termIndex != -1)
|
||||
stringVal = stringVal.Substring(0, termIndex);
|
||||
builder.Append(stringVal);
|
||||
} while (termIndex == -1);
|
||||
_value = builder.ToString().Replace(softReturn, string.Empty);
|
||||
}
|
||||
_loaded = true;
|
||||
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (_lockName)
|
||||
{
|
||||
_new = true;
|
||||
_value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _lockName.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is MemoValue m)
|
||||
{
|
||||
return ReferenceEquals(this, obj) || Value.Equals(m.Value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
dotnetdbf/Properties/MoreAssemblyInfo.cs
Normal file
3
dotnetdbf/Properties/MoreAssemblyInfo.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("DotNetDBF.Enumerable,PublicKey=00240000048000009400000006020000002400005253413100040000010001008713EA5197F8878AF1E1CDEF220E2D0A898944AD1643B851775EB8624697A183FBCD2ED8C1A58CE185B657D6381419AFF8B0DE8F8934F2B7E5DC7C19C11DE8D146B113F6794BF604BD2A11334DCF1022A485DD7A6E6BED8873D26363E9692136598B7750AD633747922657FF215347614DE2FDFA7866843F2924C9E5DB2545E1")]
|
||||
11
dotnetdbf/README.md
Normal file
11
dotnetdbf/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
dotnetdbf
|
||||
=========
|
||||
|
||||
This is a basic file parser written in C# for reading and writing xBase DBF files, particularly Clipper.
|
||||
|
||||
For .net 4.0 projects there is an enumeration framework in which makes it easy to use Linq to Objects.
|
||||
|
||||
Code derived from javadbf.
|
||||
|
||||
## Get The Binaries
|
||||
Use [NuGet](http://nuget.org/packages/dotnetdbf/) from Visual Studio
|
||||
175
dotnetdbf/Utils.cs
Normal file
175
dotnetdbf/Utils.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
Utils
|
||||
Class for contining utility functions.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public static class Utils
|
||||
{
|
||||
public const int ALIGN_LEFT = 10;
|
||||
public const int ALIGN_RIGHT = 12;
|
||||
|
||||
public static byte[] FillArray(byte[] anArray, byte value)
|
||||
{
|
||||
for (var i = 0; i < anArray.Length; i++)
|
||||
{
|
||||
anArray[i] = value;
|
||||
}
|
||||
return anArray;
|
||||
}
|
||||
|
||||
public static byte[] trimLeftSpaces(byte[] arr)
|
||||
{
|
||||
var tList = new List<byte>(arr.Length);
|
||||
|
||||
for (var i = 0; i < arr.Length; i++)
|
||||
{
|
||||
if (arr[i] != ' ')
|
||||
{
|
||||
tList.Add(arr[i]);
|
||||
}
|
||||
}
|
||||
return tList.ToArray();
|
||||
}
|
||||
|
||||
public static byte[] textPadding(string text,
|
||||
Encoding charEncoding,
|
||||
int length)
|
||||
{
|
||||
return textPadding(text, charEncoding, length, ALIGN_LEFT);
|
||||
}
|
||||
|
||||
public static byte[] textPadding(string text,
|
||||
Encoding charEncoding,
|
||||
int length,
|
||||
int alignment)
|
||||
{
|
||||
return
|
||||
textPadding(text,
|
||||
charEncoding,
|
||||
length,
|
||||
alignment,
|
||||
DBFFieldType.Space);
|
||||
}
|
||||
|
||||
public static byte[] textPadding(string text,
|
||||
Encoding charEncoding,
|
||||
int length,
|
||||
int alignment,
|
||||
byte paddingByte)
|
||||
{
|
||||
var tEncoding = charEncoding;
|
||||
var inputBytes = tEncoding.GetBytes(text);
|
||||
if (inputBytes.Length >= length)
|
||||
{
|
||||
return inputBytes.Take(length).ToArray();
|
||||
}
|
||||
|
||||
var byte_array = FillArray(new byte[length], paddingByte);
|
||||
|
||||
switch (alignment)
|
||||
{
|
||||
case ALIGN_LEFT:
|
||||
Array.Copy(inputBytes,
|
||||
0,
|
||||
byte_array,
|
||||
0,
|
||||
inputBytes.Length);
|
||||
break;
|
||||
|
||||
case ALIGN_RIGHT:
|
||||
var t_offset = length - text.Length;
|
||||
Array.Copy(inputBytes,
|
||||
0,
|
||||
byte_array,
|
||||
t_offset,
|
||||
inputBytes.Length);
|
||||
break;
|
||||
}
|
||||
|
||||
return byte_array;
|
||||
}
|
||||
|
||||
public static byte[] NumericFormating(IFormattable doubleNum,
|
||||
Encoding charEncoding,
|
||||
int fieldLength,
|
||||
int sizeDecimalPart)
|
||||
{
|
||||
var sizeWholePart = fieldLength
|
||||
-
|
||||
(sizeDecimalPart > 0 ? (sizeDecimalPart + 1) : 0);
|
||||
|
||||
var format = new StringBuilder(fieldLength);
|
||||
|
||||
for (var i = 0; i < sizeWholePart; i++)
|
||||
{
|
||||
format.Append(i + 1 == sizeWholePart ? "0" : "#");
|
||||
}
|
||||
|
||||
if (sizeDecimalPart > 0)
|
||||
{
|
||||
format.Append(".");
|
||||
|
||||
for (var i = 0; i < sizeDecimalPart; i++)
|
||||
{
|
||||
format.Append("0");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return
|
||||
textPadding(
|
||||
doubleNum.ToString(format.ToString(),
|
||||
NumberFormatInfo.InvariantInfo),
|
||||
charEncoding,
|
||||
fieldLength,
|
||||
ALIGN_RIGHT);
|
||||
}
|
||||
|
||||
public static bool contains(byte[] arr, byte value)
|
||||
{
|
||||
return
|
||||
Array.Exists(arr,
|
||||
delegate(byte anItem) { return anItem == value; });
|
||||
}
|
||||
|
||||
|
||||
public static Type TypeForNativeDBType(NativeDbType aType)
|
||||
{
|
||||
switch (aType)
|
||||
{
|
||||
case NativeDbType.Char:
|
||||
return typeof(string);
|
||||
case NativeDbType.Date:
|
||||
return typeof(DateTime);
|
||||
case NativeDbType.Numeric:
|
||||
return typeof(decimal);
|
||||
case NativeDbType.Logical:
|
||||
return typeof(bool);
|
||||
case NativeDbType.Float:
|
||||
return typeof(decimal);
|
||||
case NativeDbType.Memo:
|
||||
return typeof(MemoValue);
|
||||
default:
|
||||
return typeof(Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
dotnetdbf/original java src/DBFBase.java
Normal file
36
dotnetdbf/original java src/DBFBase.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
$Id: DBFBase.java,v 1.3 2004/03/31 15:59:40 anil Exp $
|
||||
Serves as the base class of DBFReader adn DBFWriter.
|
||||
|
||||
@author: anil@linuxense.com
|
||||
|
||||
Support for choosing implemented character Sets as
|
||||
suggested by Nick Voznesensky <darkers@mail.ru>
|
||||
*/
|
||||
/**
|
||||
Base class for DBFReader and DBFWriter.
|
||||
*/
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
public abstract class DBFBase {
|
||||
|
||||
protected String characterSetName = "8859_1";
|
||||
protected final int END_OF_DATA = 0x1A;
|
||||
|
||||
/*
|
||||
If the library is used in a non-latin environment use this method to set
|
||||
corresponding character set. More information:
|
||||
http://www.iana.org/assignments/character-sets
|
||||
Also see the documentation of the class java.nio.charset.Charset
|
||||
*/
|
||||
public String getCharactersetName() {
|
||||
|
||||
return this.characterSetName;
|
||||
}
|
||||
|
||||
public void setCharactersetName( String characterSetName) {
|
||||
|
||||
this.characterSetName = characterSetName;
|
||||
}
|
||||
|
||||
}
|
||||
27
dotnetdbf/original java src/DBFException.java
Normal file
27
dotnetdbf/original java src/DBFException.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
DBFException
|
||||
Represents exceptions happen in the JAvaDBF classes.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
author: anil@linuxense.com
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: DBFException.java,v 1.2 2004/03/31 10:40:18 anil Exp $
|
||||
*/
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DBFException extends IOException {
|
||||
|
||||
public DBFException() {
|
||||
|
||||
super();
|
||||
}
|
||||
|
||||
public DBFException( String msg) {
|
||||
|
||||
super( msg);
|
||||
}
|
||||
}
|
||||
283
dotnetdbf/original java src/DBFField.java
Normal file
283
dotnetdbf/original java src/DBFField.java
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
DBFField
|
||||
Class represents a "field" (or column) definition of a DBF data structure.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
author: anil@linuxense.com
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: DBFField.java,v 1.7 2004/03/31 10:50:11 anil Exp $
|
||||
*/
|
||||
|
||||
package com.linuxense.javadbf;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
DBFField represents a field specification in an dbf file.
|
||||
|
||||
DBFField objects are either created and added to a DBFWriter object or obtained
|
||||
from DBFReader object through getField( int) query.
|
||||
|
||||
*/
|
||||
public class DBFField {
|
||||
|
||||
public static final byte FIELD_TYPE_C = (byte)'C';
|
||||
public static final byte FIELD_TYPE_L = (byte)'L';
|
||||
public static final byte FIELD_TYPE_N = (byte)'N';
|
||||
public static final byte FIELD_TYPE_F = (byte)'F';
|
||||
public static final byte FIELD_TYPE_D = (byte)'D';
|
||||
public static final byte FIELD_TYPE_M = (byte)'M';
|
||||
|
||||
/* Field struct variables start here */
|
||||
byte[] fieldName = new byte[ 11]; /* 0-10*/
|
||||
byte dataType; /* 11 */
|
||||
int reserv1; /* 12-15 */
|
||||
int fieldLength; /* 16 */
|
||||
byte decimalCount; /* 17 */
|
||||
short reserv2; /* 18-19 */
|
||||
byte workAreaId; /* 20 */
|
||||
short reserv3; /* 21-22 */
|
||||
byte setFieldsFlag; /* 23 */
|
||||
byte[] reserv4 = new byte[ 7]; /* 24-30 */
|
||||
byte indexFieldFlag; /* 31 */
|
||||
/* Field struct variables end here */
|
||||
|
||||
/* other class variables */
|
||||
int nameNullIndex = 0;
|
||||
|
||||
/**
|
||||
Creates a DBFField object from the data read from the given DataInputStream.
|
||||
|
||||
The data in the DataInputStream object is supposed to be organised correctly
|
||||
and the stream "pointer" is supposed to be positioned properly.
|
||||
|
||||
@param in DataInputStream
|
||||
@return Returns the created DBFField object.
|
||||
@throws IOException If any stream reading problems occures.
|
||||
*/
|
||||
protected static DBFField createField( DataInput in)
|
||||
throws IOException {
|
||||
|
||||
DBFField field = new DBFField();
|
||||
|
||||
byte t_byte = in.readByte(); /* 0 */
|
||||
if( t_byte == (byte)0x0d) {
|
||||
|
||||
//System.out.println( "End of header found");
|
||||
return null;
|
||||
}
|
||||
|
||||
in.readFully( field.fieldName, 1, 10); /* 1-10 */
|
||||
field.fieldName[0] = t_byte;
|
||||
|
||||
for( int i=0; i<field.fieldName.length; i++) {
|
||||
|
||||
if( field.fieldName[ i] == (byte)0) {
|
||||
|
||||
field.nameNullIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
field.dataType = in.readByte(); /* 11 */
|
||||
field.reserv1 = Utils.readLittleEndianInt( in); /* 12-15 */
|
||||
field.fieldLength = in.readUnsignedByte(); /* 16 */
|
||||
field.decimalCount = in.readByte(); /* 17 */
|
||||
field.reserv2 = Utils.readLittleEndianShort( in); /* 18-19 */
|
||||
field.workAreaId = in.readByte(); /* 20 */
|
||||
field.reserv2 = Utils.readLittleEndianShort( in); /* 21-22 */
|
||||
field.setFieldsFlag = in.readByte(); /* 23 */
|
||||
in.readFully( field.reserv4); /* 24-30 */
|
||||
field.indexFieldFlag = in.readByte(); /* 31 */
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
Writes the content of DBFField object into the stream as per
|
||||
DBF format specifications.
|
||||
|
||||
@param os OutputStream
|
||||
@throws IOException if any stream related issues occur.
|
||||
*/
|
||||
protected void write( DataOutput out)
|
||||
throws IOException {
|
||||
|
||||
//DataOutputStream out = new DataOutputStream( os);
|
||||
|
||||
// Field Name
|
||||
out.write( fieldName); /* 0-10 */
|
||||
out.write( new byte[ 11 - fieldName.length]);
|
||||
|
||||
// data type
|
||||
out.writeByte( dataType); /* 11 */
|
||||
out.writeInt( 0x00); /* 12-15 */
|
||||
out.writeByte( fieldLength); /* 16 */
|
||||
out.writeByte( decimalCount); /* 17 */
|
||||
out.writeShort( (short)0x00); /* 18-19 */
|
||||
out.writeByte( (byte)0x00); /* 20 */
|
||||
out.writeShort( (short)0x00); /* 21-22 */
|
||||
out.writeByte( (byte)0x00); /* 23 */
|
||||
out.write( new byte[7]); /* 24-30*/
|
||||
out.writeByte( (byte)0x00); /* 31 */
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the name of the field.
|
||||
|
||||
@return Name of the field as String.
|
||||
*/
|
||||
public String getName() {
|
||||
|
||||
return new String( this.fieldName, 0, nameNullIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the data type of the field.
|
||||
|
||||
@return Data type as byte.
|
||||
*/
|
||||
public byte getDataType() {
|
||||
|
||||
return dataType;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns field length.
|
||||
|
||||
@return field length as int.
|
||||
*/
|
||||
public int getFieldLength() {
|
||||
|
||||
return fieldLength;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the decimal part. This is applicable
|
||||
only if the field type if of numeric in nature.
|
||||
|
||||
If the field is specified to hold integral values
|
||||
the value returned by this method will be zero.
|
||||
|
||||
@return decimal field size as int.
|
||||
*/
|
||||
public int getDecimalCount() {
|
||||
|
||||
return decimalCount;
|
||||
}
|
||||
|
||||
// Setter methods
|
||||
|
||||
// byte[] fieldName = new byte[ 11]; /* 0-10*/
|
||||
// byte dataType; /* 11 */
|
||||
// int reserv1; /* 12-15 */
|
||||
// byte fieldLength; /* 16 */
|
||||
// byte decimalCount; /* 17 */
|
||||
// short reserv2; /* 18-19 */
|
||||
// byte workAreaId; /* 20 */
|
||||
// short reserv3; /* 21-22 */
|
||||
// byte setFieldsFlag; /* 23 */
|
||||
// byte[] reserv4 = new byte[ 7]; /* 24-30 */
|
||||
// byte indexFieldFlag; /* 31 */
|
||||
|
||||
/**
|
||||
* @deprecated This method is depricated as of version 0.3.3.1 and is replaced by {@link #setName( String)}.
|
||||
*/
|
||||
public void setFieldName( String value) {
|
||||
|
||||
setName( value);
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the name of the field.
|
||||
|
||||
@param name of the field as String.
|
||||
@since 0.3.3.1
|
||||
*/
|
||||
public void setName( String value) {
|
||||
|
||||
if( value == null) {
|
||||
|
||||
throw new IllegalArgumentException( "Field name cannot be null");
|
||||
}
|
||||
|
||||
if( value.length() == 0 || value.length() > 10) {
|
||||
|
||||
throw new IllegalArgumentException( "Field name should be of length 0-10");
|
||||
}
|
||||
|
||||
this.fieldName = value.getBytes();
|
||||
this.nameNullIndex = this.fieldName.length;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the data type of the field.
|
||||
|
||||
@param type of the field. One of the following:<br>
|
||||
C, L, N, F, D, M
|
||||
*/
|
||||
public void setDataType( byte value) {
|
||||
|
||||
switch( value) {
|
||||
|
||||
case 'D':
|
||||
this.fieldLength = 8; /* fall through */
|
||||
case 'C':
|
||||
case 'L':
|
||||
case 'N':
|
||||
case 'F':
|
||||
case 'M':
|
||||
|
||||
this.dataType = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException( "Unknown data type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Length of the field.
|
||||
This method should be called before calling setDecimalCount().
|
||||
|
||||
@param Length of the field as int.
|
||||
*/
|
||||
public void setFieldLength( int value) {
|
||||
|
||||
if( value <= 0) {
|
||||
|
||||
throw new IllegalArgumentException( "Field length should be a positive number");
|
||||
}
|
||||
|
||||
if( this.dataType == FIELD_TYPE_D) {
|
||||
|
||||
throw new UnsupportedOperationException( "Cannot do this on a Date field");
|
||||
}
|
||||
|
||||
fieldLength = value;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the decimal place size of the field.
|
||||
Before calling this method the size of the field
|
||||
should be set by calling setFieldLength().
|
||||
|
||||
@param Size of the decimal field.
|
||||
*/
|
||||
public void setDecimalCount( int value) {
|
||||
|
||||
if( value < 0) {
|
||||
|
||||
throw new IllegalArgumentException( "Decimal length should be a positive number");
|
||||
}
|
||||
|
||||
if( value > fieldLength) {
|
||||
|
||||
throw new IllegalArgumentException( "Decimal length should be less than field length");
|
||||
}
|
||||
|
||||
decimalCount = (byte)value;
|
||||
}
|
||||
|
||||
}
|
||||
167
dotnetdbf/original java src/DBFHeader.java
Normal file
167
dotnetdbf/original java src/DBFHeader.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
DBFHeader
|
||||
Class for reading the metadata assuming that the given
|
||||
InputStream carries DBF data.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
Author: anil@linuxense.com
|
||||
License: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
class DBFHeader {
|
||||
|
||||
static final byte SIG_DBASE_III = (byte)0x03;
|
||||
/* DBF structure start here */
|
||||
|
||||
byte signature; /* 0 */
|
||||
byte year; /* 1 */
|
||||
byte month; /* 2 */
|
||||
byte day; /* 3 */
|
||||
int numberOfRecords; /* 4-7 */
|
||||
short headerLength; /* 8-9 */
|
||||
short recordLength; /* 10-11 */
|
||||
short reserv1; /* 12-13 */
|
||||
byte incompleteTransaction; /* 14 */
|
||||
byte encryptionFlag; /* 15 */
|
||||
int freeRecordThread; /* 16-19 */
|
||||
int reserv2; /* 20-23 */
|
||||
int reserv3; /* 24-27 */
|
||||
byte mdxFlag; /* 28 */
|
||||
byte languageDriver; /* 29 */
|
||||
short reserv4; /* 30-31 */
|
||||
DBFField []fieldArray; /* each 32 bytes */
|
||||
byte terminator1; /* n+1 */
|
||||
|
||||
//byte[] databaseContainer; /* 263 bytes */
|
||||
/* DBF structure ends here */
|
||||
|
||||
DBFHeader() {
|
||||
|
||||
this.signature = SIG_DBASE_III;
|
||||
this.terminator1 = 0x0D;
|
||||
}
|
||||
|
||||
void read( DataInput dataInput) throws IOException {
|
||||
|
||||
signature = dataInput.readByte(); /* 0 */
|
||||
year = dataInput.readByte(); /* 1 */
|
||||
month = dataInput.readByte(); /* 2 */
|
||||
day = dataInput.readByte(); /* 3 */
|
||||
numberOfRecords = Utils.readLittleEndianInt( dataInput); /* 4-7 */
|
||||
|
||||
headerLength = Utils.readLittleEndianShort( dataInput); /* 8-9 */
|
||||
recordLength = Utils.readLittleEndianShort( dataInput); /* 10-11 */
|
||||
|
||||
reserv1 = Utils.readLittleEndianShort( dataInput); /* 12-13 */
|
||||
incompleteTransaction = dataInput.readByte(); /* 14 */
|
||||
encryptionFlag = dataInput.readByte(); /* 15 */
|
||||
freeRecordThread = Utils.readLittleEndianInt( dataInput); /* 16-19 */
|
||||
reserv2 = dataInput.readInt(); /* 20-23 */
|
||||
reserv3 = dataInput.readInt(); /* 24-27 */
|
||||
mdxFlag = dataInput.readByte(); /* 28 */
|
||||
languageDriver = dataInput.readByte(); /* 29 */
|
||||
reserv4 = Utils.readLittleEndianShort( dataInput); /* 30-31 */
|
||||
|
||||
Vector v_fields = new Vector();
|
||||
|
||||
DBFField field = DBFField.createField( dataInput); /* 32 each */
|
||||
while( field != null) {
|
||||
|
||||
v_fields.addElement( field);
|
||||
field = DBFField.createField( dataInput);
|
||||
}
|
||||
|
||||
fieldArray = new DBFField[ v_fields.size()];
|
||||
|
||||
for( int i=0; i<fieldArray.length; i++) {
|
||||
|
||||
fieldArray[ i] = (DBFField)v_fields.elementAt( i);
|
||||
}
|
||||
//System.out.println( "Number of fields: " + fieldArray.length);
|
||||
|
||||
}
|
||||
|
||||
void write( DataOutput dataOutput) throws IOException {
|
||||
|
||||
dataOutput.writeByte( signature); /* 0 */
|
||||
|
||||
GregorianCalendar calendar = new GregorianCalendar();
|
||||
year = (byte)( calendar.get( Calendar.YEAR) - 1900);
|
||||
month = (byte)( calendar.get( Calendar.MONTH)+1);
|
||||
day = (byte)( calendar.get( Calendar.DAY_OF_MONTH));
|
||||
|
||||
dataOutput.writeByte( year); /* 1 */
|
||||
dataOutput.writeByte( month); /* 2 */
|
||||
dataOutput.writeByte( day); /* 3 */
|
||||
|
||||
//System.out.println( "Number of records in O/S: " + numberOfRecords);
|
||||
numberOfRecords = Utils.littleEndian( numberOfRecords);
|
||||
dataOutput.writeInt( numberOfRecords); /* 4-7 */
|
||||
|
||||
headerLength = findHeaderLength();
|
||||
dataOutput.writeShort( Utils.littleEndian( headerLength)); /* 8-9 */
|
||||
|
||||
recordLength = findRecordLength();
|
||||
dataOutput.writeShort( Utils.littleEndian( recordLength)); /* 10-11 */
|
||||
|
||||
dataOutput.writeShort( Utils.littleEndian( reserv1)); /* 12-13 */
|
||||
dataOutput.writeByte( incompleteTransaction); /* 14 */
|
||||
dataOutput.writeByte( encryptionFlag); /* 15 */
|
||||
dataOutput.writeInt( Utils.littleEndian( freeRecordThread));/* 16-19 */
|
||||
dataOutput.writeInt( Utils.littleEndian( reserv2)); /* 20-23 */
|
||||
dataOutput.writeInt( Utils.littleEndian( reserv3)); /* 24-27 */
|
||||
|
||||
dataOutput.writeByte( mdxFlag); /* 28 */
|
||||
dataOutput.writeByte( languageDriver); /* 29 */
|
||||
dataOutput.writeShort( Utils.littleEndian( reserv4)); /* 30-31 */
|
||||
|
||||
for( int i=0; i<fieldArray.length; i++) {
|
||||
|
||||
//System.out.println( "Length: " + fieldArray[i].getFieldLength());
|
||||
fieldArray[i].write( dataOutput);
|
||||
}
|
||||
|
||||
dataOutput.writeByte( terminator1); /* n+1 */
|
||||
}
|
||||
|
||||
private short findHeaderLength() {
|
||||
|
||||
return (short)(
|
||||
1+
|
||||
3+
|
||||
4+
|
||||
2+
|
||||
2+
|
||||
2+
|
||||
1+
|
||||
1+
|
||||
4+
|
||||
4+
|
||||
4+
|
||||
1+
|
||||
1+
|
||||
2+
|
||||
(32*fieldArray.length)+
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
private short findRecordLength() {
|
||||
|
||||
int recordLength = 0;
|
||||
for( int i=0; i<fieldArray.length; i++) {
|
||||
|
||||
recordLength += fieldArray[i].getFieldLength();
|
||||
}
|
||||
|
||||
return (short)(recordLength + 1);
|
||||
}
|
||||
}
|
||||
315
dotnetdbf/original java src/DBFReader.java
Normal file
315
dotnetdbf/original java src/DBFReader.java
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
DBFReader
|
||||
Class for reading the records assuming that the given
|
||||
InputStream comtains DBF data.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
Author: anil@linuxense.com
|
||||
License: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: DBFReader.java,v 1.8 2004/03/31 10:54:03 anil Exp $
|
||||
*/
|
||||
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
DBFReader class can creates objects to represent DBF data.
|
||||
|
||||
This Class is used to read data from a DBF file. Meta data and
|
||||
records can be queried against this document.
|
||||
|
||||
<p>
|
||||
DBFReader cannot write anythng to a DBF file. For creating DBF files
|
||||
use DBFWriter.
|
||||
|
||||
<p>
|
||||
Fetching rocord is possible only in the forward direction and
|
||||
cannot re-wound. In such situation, a suggested approach is to reconstruct the object.
|
||||
|
||||
<p>
|
||||
The nextRecord() method returns an array of Objects and the types of these
|
||||
Object are as follows:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>xBase Type</th><th>Java Type</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>C</td><td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>N</td><td>Integer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>F</td><td>Double</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>L</td><td>Boolean</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>D</td><td>java.util.Date</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
*/
|
||||
public class DBFReader extends DBFBase {
|
||||
|
||||
DataInputStream dataInputStream;
|
||||
DBFHeader header;
|
||||
|
||||
/* Class specific variables */
|
||||
boolean isClosed = true;
|
||||
|
||||
/**
|
||||
Initializes a DBFReader object.
|
||||
|
||||
When this constructor returns the object
|
||||
will have completed reading the hader (meta date) and
|
||||
header information can be quried there on. And it will
|
||||
be ready to return the first row.
|
||||
|
||||
@param InputStream where the data is read from.
|
||||
*/
|
||||
public DBFReader( InputStream in) throws DBFException {
|
||||
|
||||
try {
|
||||
|
||||
this.dataInputStream = new DataInputStream( in);
|
||||
this.isClosed = false;
|
||||
this.header = new DBFHeader();
|
||||
this.header.read( this.dataInputStream);
|
||||
|
||||
/* it might be required to leap to the start of records at times */
|
||||
int t_dataStartIndex = this.header.headerLength - ( 32 + (32*this.header.fieldArray.length)) - 1;
|
||||
if( t_dataStartIndex > 0) {
|
||||
|
||||
dataInputStream.skip( t_dataStartIndex);
|
||||
}
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
|
||||
StringBuffer sb = new StringBuffer( this.header.year + "/" + this.header.month + "/" + this.header.day + "\n"
|
||||
+ "Total records: " + this.header.numberOfRecords +
|
||||
"\nHEader length: " + this.header.headerLength +
|
||||
"");
|
||||
|
||||
for( int i=0; i<this.header.fieldArray.length; i++) {
|
||||
|
||||
sb.append( this.header.fieldArray[i].getName());
|
||||
sb.append( "\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of records in the DBF.
|
||||
*/
|
||||
public int getRecordCount() {
|
||||
|
||||
return this.header.numberOfRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the asked Field. In case of an invalid index,
|
||||
it returns a ArrayIndexOutofboundsException.
|
||||
|
||||
@param index. Index of the field. Index of the first field is zero.
|
||||
*/
|
||||
public DBFField getField( int index)
|
||||
throws DBFException {
|
||||
|
||||
if( isClosed) {
|
||||
|
||||
throw new DBFException( "Source is not open");
|
||||
}
|
||||
|
||||
return this.header.fieldArray[ index];
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of field in the DBF.
|
||||
*/
|
||||
public int getFieldCount()
|
||||
throws DBFException {
|
||||
|
||||
if( isClosed) {
|
||||
|
||||
throw new DBFException( "Source is not open");
|
||||
}
|
||||
|
||||
if( this.header.fieldArray != null) {
|
||||
|
||||
return this.header.fieldArray.length;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
Reads the returns the next row in the DBF stream.
|
||||
@returns The next row as an Object array. Types of the elements
|
||||
these arrays follow the convention mentioned in the class description.
|
||||
*/
|
||||
public Object[] nextRecord()
|
||||
throws DBFException {
|
||||
|
||||
if( isClosed) {
|
||||
|
||||
throw new DBFException( "Source is not open");
|
||||
}
|
||||
|
||||
Object recordObjects[] = new Object[ this.header.fieldArray.length];
|
||||
|
||||
try {
|
||||
|
||||
boolean isDeleted = false;
|
||||
do {
|
||||
|
||||
if( isDeleted) {
|
||||
|
||||
dataInputStream.skip( this.header.recordLength-1);
|
||||
}
|
||||
|
||||
int t_byte = dataInputStream.readByte();
|
||||
if( t_byte == END_OF_DATA) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
isDeleted = ( t_byte == '*');
|
||||
} while( isDeleted);
|
||||
|
||||
for( int i=0; i<this.header.fieldArray.length; i++) {
|
||||
|
||||
switch( this.header.fieldArray[i].getDataType()) {
|
||||
|
||||
case 'C':
|
||||
|
||||
byte b_array[] = new byte[ this.header.fieldArray[i].getFieldLength()];
|
||||
dataInputStream.read( b_array);
|
||||
recordObjects[i] = new String( b_array, characterSetName);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
|
||||
byte t_byte_year[] = new byte[ 4];
|
||||
dataInputStream.read( t_byte_year);
|
||||
|
||||
byte t_byte_month[] = new byte[ 2];
|
||||
dataInputStream.read( t_byte_month);
|
||||
|
||||
byte t_byte_day[] = new byte[ 2];
|
||||
dataInputStream.read( t_byte_day);
|
||||
|
||||
try {
|
||||
|
||||
GregorianCalendar calendar = new GregorianCalendar(
|
||||
Integer.parseInt( new String( t_byte_year)),
|
||||
Integer.parseInt( new String( t_byte_month)) - 1,
|
||||
Integer.parseInt( new String( t_byte_day))
|
||||
);
|
||||
|
||||
recordObjects[i] = calendar.getTime();
|
||||
}
|
||||
catch ( NumberFormatException e) {
|
||||
/* this field may be empty or may have improper value set */
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
|
||||
try {
|
||||
|
||||
byte t_float[] = new byte[ this.header.fieldArray[i].getFieldLength()];
|
||||
dataInputStream.read( t_float);
|
||||
t_float = Utils.trimLeftSpaces( t_float);
|
||||
if( t_float.length > 0 && !Utils.contains( t_float, (byte)'?')) {
|
||||
|
||||
recordObjects[i] = new Float( new String( t_float));
|
||||
}
|
||||
else {
|
||||
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
}
|
||||
catch( NumberFormatException e) {
|
||||
|
||||
throw new DBFException( "Failed to parse Float: " + e.getMessage());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
|
||||
try {
|
||||
|
||||
byte t_numeric[] = new byte[ this.header.fieldArray[i].getFieldLength()];
|
||||
dataInputStream.read( t_numeric);
|
||||
t_numeric = Utils.trimLeftSpaces( t_numeric);
|
||||
|
||||
if( t_numeric.length > 0 && !Utils.contains( t_numeric, (byte)'?')) {
|
||||
|
||||
recordObjects[i] = new Double( new String( t_numeric));
|
||||
}
|
||||
else {
|
||||
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
}
|
||||
catch( NumberFormatException e) {
|
||||
|
||||
throw new DBFException( "Failed to parse Number: " + e.getMessage());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
|
||||
byte t_logical = dataInputStream.readByte();
|
||||
if( t_logical == 'Y' || t_logical == 't' || t_logical == 'T' || t_logical == 't') {
|
||||
|
||||
recordObjects[i] = Boolean.TRUE;
|
||||
}
|
||||
else {
|
||||
|
||||
recordObjects[i] = Boolean.FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
// TODO Later
|
||||
recordObjects[i] = new String( "null");
|
||||
break;
|
||||
|
||||
default:
|
||||
recordObjects[i] = new String( "null");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( EOFException e) {
|
||||
|
||||
return null;
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( e.getMessage());
|
||||
}
|
||||
|
||||
return recordObjects;
|
||||
}
|
||||
}
|
||||
350
dotnetdbf/original java src/DBFWriter.java
Normal file
350
dotnetdbf/original java src/DBFWriter.java
Normal file
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
DBFWriter
|
||||
Class for defining a DBF structure and addin data to that structure and
|
||||
finally writing it to an OutputStream.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
author: anil@linuxense.com
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: DBFWriter.java,v 1.9 2004/03/31 10:57:16 anil Exp $
|
||||
*/
|
||||
package com.linuxense.javadbf;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
An object of this class can create a DBF file.
|
||||
|
||||
Create an object, <br>
|
||||
then define fields by creating DBFField objects and<br>
|
||||
add them to the DBFWriter object<br>
|
||||
add records using the addRecord() method and then<br>
|
||||
call write() method.
|
||||
*/
|
||||
public class DBFWriter extends DBFBase {
|
||||
|
||||
/* other class variables */
|
||||
DBFHeader header;
|
||||
Vector v_records = new Vector();
|
||||
int recordCount = 0;
|
||||
RandomAccessFile raf = null; /* Open and append records to an existing DBF */
|
||||
boolean appendMode = false;
|
||||
|
||||
/**
|
||||
Creates an empty Object.
|
||||
*/
|
||||
public DBFWriter() {
|
||||
|
||||
this.header = new DBFHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a DBFWriter which can append to records to an existing DBF file.
|
||||
@param dbfFile. The file passed in shouls be a valid DBF file.
|
||||
@exception Throws DBFException if the passed in file does exist but not a valid DBF file, or if an IO error occurs.
|
||||
*/
|
||||
public DBFWriter( File dbfFile)
|
||||
throws DBFException {
|
||||
|
||||
try {
|
||||
|
||||
this.raf = new RandomAccessFile( dbfFile, "rw");
|
||||
|
||||
/* before proceeding check whether the passed in File object
|
||||
is an empty/non-existent file or not.
|
||||
*/
|
||||
if( !dbfFile.exists() || dbfFile.length() == 0) {
|
||||
|
||||
this.header = new DBFHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
header = new DBFHeader();
|
||||
this.header.read( raf);
|
||||
|
||||
/* position file pointer at the end of the raf */
|
||||
this.raf.seek( this.raf.length()-1 /* to ignore the END_OF_DATA byte at EoF */);
|
||||
}
|
||||
catch( FileNotFoundException e) {
|
||||
|
||||
throw new DBFException( "Specified file is not found. " + e.getMessage());
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( e.getMessage() + " while reading header");
|
||||
}
|
||||
|
||||
this.recordCount = this.header.numberOfRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets fields.
|
||||
*/
|
||||
public void setFields( DBFField[] fields)
|
||||
throws DBFException {
|
||||
|
||||
if( this.header.fieldArray != null) {
|
||||
|
||||
throw new DBFException( "Fields has already been set");
|
||||
}
|
||||
|
||||
if( fields == null || fields.length == 0) {
|
||||
|
||||
throw new DBFException( "Should have at least one field");
|
||||
}
|
||||
|
||||
for( int i=0; i<fields.length; i++) {
|
||||
|
||||
if( fields[i] == null) {
|
||||
|
||||
throw new DBFException( "Field " + (i+1) + " is null");
|
||||
}
|
||||
}
|
||||
|
||||
this.header.fieldArray = fields;
|
||||
|
||||
try {
|
||||
|
||||
if( this.raf != null && this.raf.length() == 0) {
|
||||
|
||||
/*
|
||||
this is a new/non-existent file. So write header before proceeding
|
||||
*/
|
||||
this.header.write( this.raf);
|
||||
}
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( "Error accesing file");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Add a record.
|
||||
*/
|
||||
public void addRecord( Object[] values)
|
||||
throws DBFException {
|
||||
|
||||
if( this.header.fieldArray == null) {
|
||||
|
||||
throw new DBFException( "Fields should be set before adding records");
|
||||
}
|
||||
|
||||
if( values == null) {
|
||||
|
||||
throw new DBFException( "Null cannot be added as row");
|
||||
}
|
||||
|
||||
if( values.length != this.header.fieldArray.length) {
|
||||
|
||||
throw new DBFException( "Invalid record. Invalid number of fields in row");
|
||||
}
|
||||
|
||||
for( int i=0; i<this.header.fieldArray.length; i++) {
|
||||
|
||||
if( values[i] == null) {
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
switch( this.header.fieldArray[i].getDataType()) {
|
||||
|
||||
case 'C':
|
||||
if( !(values[i] instanceof String)) {
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
if( !( values[i] instanceof Boolean)) {
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
if( !( values[i] instanceof Double)) {
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
if( !( values[i] instanceof Date)) {
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
if( !(values[i] instanceof Double)) {
|
||||
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( this.raf == null) {
|
||||
|
||||
v_records.addElement( values);
|
||||
}
|
||||
else {
|
||||
|
||||
try {
|
||||
|
||||
writeRecord( this.raf, values);
|
||||
this.recordCount++;
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( "Error occured while writing record. " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Writes the set data to the OutputStream.
|
||||
*/
|
||||
public void write( OutputStream out)
|
||||
throws DBFException {
|
||||
|
||||
try {
|
||||
|
||||
if( this.raf == null) {
|
||||
|
||||
DataOutputStream outStream = new DataOutputStream( out);
|
||||
|
||||
this.header.numberOfRecords = v_records.size();
|
||||
this.header.write( outStream);
|
||||
|
||||
/* Now write all the records */
|
||||
int t_recCount = v_records.size();
|
||||
for( int i=0; i<t_recCount; i++) { /* iterate through records */
|
||||
|
||||
Object[] t_values = (Object[])v_records.elementAt( i);
|
||||
|
||||
writeRecord( outStream, t_values);
|
||||
}
|
||||
|
||||
outStream.write( END_OF_DATA);
|
||||
outStream.flush();
|
||||
}
|
||||
else {
|
||||
|
||||
/* everything is written already. just update the header for record count and the END_OF_DATA mark */
|
||||
this.header.numberOfRecords = this.recordCount;
|
||||
this.raf.seek( 0);
|
||||
this.header.write( this.raf);
|
||||
this.raf.seek( raf.length());
|
||||
this.raf.writeByte( END_OF_DATA);
|
||||
this.raf.close();
|
||||
}
|
||||
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void write()
|
||||
throws DBFException {
|
||||
|
||||
this.write( null);
|
||||
}
|
||||
|
||||
private void writeRecord( DataOutput dataOutput, Object []objectArray)
|
||||
throws IOException {
|
||||
|
||||
dataOutput.write( (byte)' ');
|
||||
for( int j=0; j<this.header.fieldArray.length; j++) { /* iterate throught fields */
|
||||
|
||||
switch( this.header.fieldArray[j].getDataType()) {
|
||||
|
||||
case 'C':
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
String str_value = objectArray[j].toString();
|
||||
dataOutput.write( Utils.textPadding( str_value, characterSetName, this.header.fieldArray[j].getFieldLength()));
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write( Utils.textPadding( "", this.characterSetName, this.header.fieldArray[j].getFieldLength()));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
GregorianCalendar calendar = new GregorianCalendar();
|
||||
calendar.setTime( (Date)objectArray[j]);
|
||||
StringBuffer t_sb = new StringBuffer();
|
||||
dataOutput.write( String.valueOf( calendar.get( Calendar.YEAR)).getBytes());
|
||||
dataOutput.write( Utils.textPadding( String.valueOf( calendar.get( Calendar.MONTH)+1), this.characterSetName, 2, Utils.ALIGN_RIGHT, (byte)'0'));
|
||||
dataOutput.write( Utils.textPadding( String.valueOf( calendar.get( Calendar.DAY_OF_MONTH)), this.characterSetName, 2, Utils.ALIGN_RIGHT, (byte)'0'));
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write( " ".getBytes());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
dataOutput.write( Utils.doubleFormating( (Double)objectArray[j], this.characterSetName, this.header.fieldArray[j].getFieldLength(), this.header.fieldArray[j].getDecimalCount()));
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write( Utils.textPadding( "?", this.characterSetName, this.header.fieldArray[j].getFieldLength(), Utils.ALIGN_RIGHT));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
dataOutput.write(
|
||||
Utils.doubleFormating( (Double)objectArray[j], this.characterSetName, this.header.fieldArray[j].getFieldLength(), this.header.fieldArray[j].getDecimalCount()));
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write(
|
||||
Utils.textPadding( "?", this.characterSetName, this.header.fieldArray[j].getFieldLength(), Utils.ALIGN_RIGHT));
|
||||
}
|
||||
|
||||
break;
|
||||
case 'L':
|
||||
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
if( (Boolean)objectArray[j] == Boolean.TRUE) {
|
||||
|
||||
dataOutput.write( (byte)'T');
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write((byte)'F');
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write( (byte)'?');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new DBFException( "Unknown field type " + this.header.fieldArray[j].getDataType());
|
||||
}
|
||||
} /* iterating through the fields */
|
||||
}
|
||||
}
|
||||
172
dotnetdbf/original java src/Utils.java
Normal file
172
dotnetdbf/original java src/Utils.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
Utils
|
||||
Class for contining utility functions.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
author: anil@linuxense.com
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: Utils.java,v 1.7 2004/03/31 16:00:34 anil Exp $
|
||||
*/
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.text.*;
|
||||
|
||||
/**
|
||||
Miscelaneous functions required by the JavaDBF package.
|
||||
*/
|
||||
public final class Utils {
|
||||
|
||||
public static final int ALIGN_LEFT = 10;
|
||||
public static final int ALIGN_RIGHT = 12;
|
||||
|
||||
private Utils(){}
|
||||
|
||||
public static int readLittleEndianInt( DataInput in)
|
||||
throws IOException {
|
||||
|
||||
int bigEndian = 0;
|
||||
for( int shiftBy=0; shiftBy<32; shiftBy+=8) {
|
||||
|
||||
bigEndian |= (in.readUnsignedByte()&0xff) << shiftBy;
|
||||
}
|
||||
|
||||
return bigEndian;
|
||||
}
|
||||
|
||||
public static short readLittleEndianShort( DataInput in)
|
||||
throws IOException {
|
||||
|
||||
int low = in.readUnsignedByte() & 0xff;
|
||||
int high = in.readUnsignedByte();
|
||||
|
||||
return (short )(high << 8 | low);
|
||||
}
|
||||
|
||||
public static byte[] trimLeftSpaces( byte [] arr) {
|
||||
|
||||
StringBuffer t_sb = new StringBuffer( arr.length);
|
||||
|
||||
for( int i=0; i<arr.length; i++) {
|
||||
|
||||
if( arr[i] != ' ') {
|
||||
|
||||
t_sb.append( (char)arr[ i]);
|
||||
}
|
||||
}
|
||||
|
||||
return t_sb.toString().getBytes();
|
||||
}
|
||||
|
||||
public static short littleEndian( short value) {
|
||||
|
||||
short num1 = value;
|
||||
short mask = (short)0xff;
|
||||
|
||||
short num2 = (short)(num1&mask);
|
||||
num2<<=8;
|
||||
mask<<=8;
|
||||
|
||||
num2 |= (num1&mask)>>8;
|
||||
|
||||
return num2;
|
||||
}
|
||||
|
||||
public static int littleEndian(int value) {
|
||||
|
||||
int num1 = value;
|
||||
int mask = 0xff;
|
||||
int num2 = 0x00;
|
||||
|
||||
num2 |= num1 & mask;
|
||||
|
||||
for( int i=1; i<4; i++) {
|
||||
|
||||
num2<<=8;
|
||||
mask <<= 8;
|
||||
num2 |= (num1 & mask)>>(8*i);
|
||||
}
|
||||
|
||||
return num2;
|
||||
}
|
||||
|
||||
public static byte[] textPadding( String text, String characterSetName, int length) throws java.io.UnsupportedEncodingException {
|
||||
|
||||
return textPadding( text, characterSetName, length, Utils.ALIGN_LEFT);
|
||||
}
|
||||
|
||||
public static byte[] textPadding( String text, String characterSetName, int length, int alignment) throws java.io.UnsupportedEncodingException {
|
||||
|
||||
return textPadding( text, characterSetName, length, alignment, (byte)' ');
|
||||
}
|
||||
|
||||
public static byte[] textPadding( String text, String characterSetName, int length, int alignment,
|
||||
byte paddingByte) throws java.io.UnsupportedEncodingException {
|
||||
|
||||
if( text.length() >= length) {
|
||||
|
||||
return text.substring( 0, length).getBytes( characterSetName);
|
||||
}
|
||||
|
||||
byte byte_array[] = new byte[ length];
|
||||
Arrays.fill( byte_array, paddingByte);
|
||||
|
||||
switch( alignment) {
|
||||
|
||||
case ALIGN_LEFT:
|
||||
System.arraycopy( text.getBytes( characterSetName), 0, byte_array, 0, text.length());
|
||||
break;
|
||||
|
||||
case ALIGN_RIGHT:
|
||||
int t_offset = length - text.length();
|
||||
System.arraycopy( text.getBytes( characterSetName), 0, byte_array, t_offset, text.length());
|
||||
break;
|
||||
}
|
||||
|
||||
return byte_array;
|
||||
}
|
||||
|
||||
public static byte[] doubleFormating( Double doubleNum, String characterSetName, int fieldLength, int sizeDecimalPart) throws java.io.UnsupportedEncodingException{
|
||||
|
||||
int sizeWholePart = fieldLength - (sizeDecimalPart>0?( sizeDecimalPart + 1):0);
|
||||
|
||||
StringBuffer format = new StringBuffer( fieldLength);
|
||||
|
||||
for( int i=0; i<sizeWholePart; i++) {
|
||||
|
||||
format.append( "#");
|
||||
}
|
||||
|
||||
if( sizeDecimalPart > 0) {
|
||||
|
||||
format.append( ".");
|
||||
|
||||
for( int i=0; i<sizeDecimalPart; i++) {
|
||||
|
||||
format.append( "0");
|
||||
}
|
||||
}
|
||||
|
||||
DecimalFormat df = new DecimalFormat( format.toString());
|
||||
|
||||
return textPadding( df.format( doubleNum.doubleValue()).toString(), characterSetName, fieldLength, ALIGN_RIGHT);
|
||||
}
|
||||
|
||||
public static boolean contains( byte[] arr, byte value) {
|
||||
|
||||
boolean found = false;
|
||||
for( int i=0; i<arr.length; i++) {
|
||||
|
||||
if( arr[i] == value) {
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
}
|
||||
BIN
dotnetdbf/sn.snk
Normal file
BIN
dotnetdbf/sn.snk
Normal file
Binary file not shown.
Reference in New Issue
Block a user