Wednesday, August 12, 2009

64 Bit Integer Literals and Microsoft Visual C++ 6.0

In the course of porting an implementation of the SHA-x series of message digest algorithms (SHA-224, SHA-256, SHA-384, and SHA-512) from Unix C to Microsoft C, using the Visual C++ 6.0 compiler, I needed to convert several hard coded initialization vectors, each composed of 64 bit integer literals, to a format acceptable to the Visual C++ compiler. This was my first serious foray into 64 bit integer math, which is essential to the higher order SHA-x algorithms.

In the Unix C code, the literals look like this.

0xcbbb9d5dc1059ed8ULL

The Microsoft Visual C++ compiler needs something like this.

0xcbbb9d5dc1059ed8

Following is the shortest of the initialization vectors.

#if defined(_MSC_VER) defined(__BORLANDC__)
uint64 sha384_h0[8] =
{0xcbbb9d5dc1059ed8, 0x629a292a367cd507,
0x9159015a3070dd17, 0x152fecd8f70e5939,
0x67332667ffc00b31, 0x8eb44a8768581511,
0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4};
#else
uint64 sha384_h0[8] =
{0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL,
0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL,
0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL,
0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL};
#endif

The second block, between #else and #endif, contains the original definition, which probably works fine on any C compiler that runs on Unix or any of its many variations, especially if the target CPU has a 64 bit word, but a half-dozen or so of these made Visual C++ hurl.

I suspected that I needed only to lose the ULL size suffixes, and almost tried the change without doing any research. Amazingly, the following query, fed into Google, promptly returned exactly one link, MatLab® 7: External Interfaces. When I saw the title, I felt certain that I had hit pay dirt.

"64 bit integer literal" "visual c++ 6.0"

Repeating the first of the two search tokens, "64 bit integer literal," within the returned "page," which is a massive Adobe PDF document, instantly took me to the following section, on page 186

Specifying Constant Literal Values

To assign signed and unsigned 64-bit integer literal values, use typedefinitions int64_T and uint64_T.

On UNIX systems, to assign a literal value to an integer variable where thevalue to be assigned is greater than 2 31-1 signed, you must suffix the valuewith LL. If the value is greater than 2 32-1 unsigned, then use LLU as thesuffix. These suffixes apply only to UNIX systems and are considered invalidon the Microsoft Windows systems.

Note The LL and LLU suffixes are not required for hardcoded (literal) valuesless than 2 G (2 31-1), even if they are assigned to a 64-bit int type.

The following example declares a 64-bit integer variable initialized with alarge literal int value, and two 64-bit integer variables:

void mexFunction(int nlhs, mxArray *plhs[], int nrhs,
const mxArray *prhs[])
#if defined(_MSC_VER) defined(__BORLANDC__) /* Windows */
int64_T large_offset_example = 9000222000;
#else /* UNIX */
int64_T large_offset_example = 9000222000LL;
#endif

int64_T offset = 0;
int64_T position = 0;

This was exactly the information that I needed. Application of the same technique to my source code quickly yielded code that compiles cleanly, without errors or warnings.

I've used hundreds of similar queries with Google and other search engines, followed by hours of wasted time reading irrelevant material. More often than not, they have yielded either nothing, or a hopelessly long list of mostly useless articles.

Persistence pays, and, sometimes, you really do get lucky.

Monday, August 10, 2009

File.WriteAllText Quirks

Background

Today, in the course of adding a couple of features to a new tool, which I created last week, for internal use, I started to put the code behind its Save button through its paces, only to discover that the code displayed the following error message.

Access to the path d:\Path\FileName is denied.

Since I had recently opened the file in my text editor (UltraEdit) which I know, for certain, acquires exclusive access to files that you open for editing, I restarted the computer.

Alas, the problem persisted.

Analysis

The only difference in the environment between last week, when I wrote and tested the initial version of the program, and today, is that its output file is now marked Read Only, System, and Hidden. Since a companion Visual Basic script reads the very same file, with the same three flags set on it, I didn't expect trouble from the C# program that I wrote last week.

After wasting a couple of hours reading articles returned by several Google searches, I concluded that I might be the first person to identify this problem and write about it.

After tinkering with the file attributes, I discovered that the only way to get the File.WriteAllText() method to work was to temporarily remove all three attributes, although I suspect it's actually the Hidden attribute that is the offender.

Fortunately, this task was made much easier by the fact that I already had a FileInfoExtension class, which extends the standard System.IO.FileInfo class by adding a set of simple methods for setting, clearing, and restoring the Read Only file attribute. Leveraging my latest general purpose programming editor, UltraEdit, and the Visual Studio editor, it took only a few minutes to extend the class to cover the System, and Hidden attributes. For good measure, I also extended it to cover the Archive attribute. I decided to leave the remaining attributes for another day, since I don't have an immediate need for them.

In the C# program, the change required just seven new lines of code, highlighted in blue.

 FileInfoExtension fix = new FileInfoExtension ( strFQFN );
 /*
  --------------------------------------------------------
  The File.WriteAllText() method cannot see files unless
  their Hidden attribute is removed.
  --------------------------------------------------------
 */
 fix.SystemClear ( );
 fix.HiddenClear ( );
 fix.ReadOnlyClear ( );
 File.WriteAllText (
  strFQFN ,
  strData ,
  Encoding.ASCII );
 fix.ReadOnlySet ( );
 fix.SystemSet ( );
 fix.HiddenSet ( );

The first step is to create a new FileInfoExtension object, passing the name of the file, strFQFN, to its constructor. Next, the three attributes are cleared. The Archive attribute is ignored, because the call to File.WriteAllText() sets it to True. Finally, the three attributes are reset to to True. Since this is a tiny data file, this happens so fast that no user is likely to see the brief change.

I'll save a discussion of the FileInfoExtension class for another day. I'll just say that, if your code also needs a System.IO.FileInfo object to go with the same file, the FileInfoExtension class exposes one as a property.