Example #1
0
        private static bool RunNHSNumberTests()
        {
            Console.WriteLine();
            Console.WriteLine("Running NHSNumber validation test");

            OpenPseudonymiser.Crypto crypto = new Crypto();

            bool   success            = true;
            string processedNHSNumber = "";

            // A call to ProcessNHSNumber will strip all non numeric characters from the string
            processedNHSNumber = crypto.ProcessNHSNumber("4505577104");

            // A call to the static "IsValidNHSNumber" method will return a true if the string passes the NHS number validation checksum as described here:
            // http://www.datadictionary.nhs.uk/data_dictionary/attributes/n/nhs_number_de.asp
            success = success & (NHSNumberValidator.IsValidNHSNumber(processedNHSNumber));
            Console.WriteLine("NHSNumber validation test 1: " + success);

            processedNHSNumber = crypto.ProcessNHSNumber("1");
            success            = success & !(NHSNumberValidator.IsValidNHSNumber(processedNHSNumber));
            Console.WriteLine("NHSNumber validation test 2: " + success);

            processedNHSNumber = crypto.ProcessNHSNumber("fish");
            success            = success & !(NHSNumberValidator.IsValidNHSNumber(processedNHSNumber));
            Console.WriteLine("NHSNumber validation test 3: " + success);

            processedNHSNumber = crypto.ProcessNHSNumber("1267716276817687612");
            success            = success & !(NHSNumberValidator.IsValidNHSNumber(processedNHSNumber));
            Console.WriteLine("NHSNumber validation test 4: " + success);

            processedNHSNumber = crypto.ProcessNHSNumber("450 557 7104");
            success            = success & (NHSNumberValidator.IsValidNHSNumber(processedNHSNumber));
            Console.WriteLine("NHSNumber validation test 5: " + success);

            processedNHSNumber = crypto.ProcessNHSNumber("450-557-7104");
            success            = success & (NHSNumberValidator.IsValidNHSNumber(processedNHSNumber));
            Console.WriteLine("NHSNumber validation test 6: " + success);

            Console.WriteLine("NHSNumber validation test: " + success);
            return(success);
        }
Example #2
0
 public static bool IsValidNHSNumber(string inputString)
 {
     return(NHSNumberValidator.IsValidNHSNumber(inputString));
 }
        private bool MainWork(string filename, int indexOfNHSNumber, Dispatcher dispatcher, ref bool wasCancelled)
        {
            _validNHSNumCount   = 0;
            _inValidNHSNumCount = 0;
            _missingNHSNumCount = 0;
            _rowsProcessed      = 0;

            // the thing that gets the digest..
            Crypto crypto = new Crypto();

            if (usingEncryptedSalt)
            {
                crypto.SetEncryptedSalt(File.ReadAllBytes(encryptedSaltFile));
            }
            else
            {
                crypto.SetPlainTextSalt(_salt);
            }

            FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);

            FileStream writeStream;

            try
            {
                writeStream = new FileStream(_outputFolder + "\\" + "OpenPseudonymised_" + _outputFileNameOnly, FileMode.Create, FileAccess.Write);
            }
            catch (IOException)
            {
                ErrorProgressDelegate error = new ErrorProgressDelegate(ErrorProgressText);
                dispatcher.BeginInvoke(error, "OpenPseudonymiser cannot create the Output file. Is the output file already open?");
                return(false);
            }

            _inputFileStreamLength = fileStream.Length;
            long totalCharsRead = 0;

            SortedList <string, int> inputFields;
            SortedList <int, string> outputFields;

            GetInputAndOutputFields(out inputFields, out outputFields);

            WriteRunLogFile(inputFields, outputFields);

            using (StreamWriter streamWriter = new StreamWriter(writeStream))
            {
                using (StreamReader streamReader = new StreamReader(fileStream))
                {
                    // 'read off' the first line, these are the input columns headings
                    string[] inputHeadings = streamReader.ReadLine().Split(',');

                    // write the first line as the selected column headings
                    string lineToWrite = "Digest,";
                    foreach (int key in outputFields.Keys) // keys in the output are indexes (opposite to input SortedList)
                    {
                        lineToWrite += outputFields[key] + ",";
                    }

                    // Do we want to do any NHSNumber checksum validation?
                    if (_performNHSNumberValidation)
                    {
                        lineToWrite += "validNHS,";
                    }

                    // strip trailing comma
                    lineToWrite = lineToWrite.Substring(0, lineToWrite.Length - 1);
                    streamWriter.WriteLine(lineToWrite);

                    // We have no way of knowing how many lines there are in the file without opening the whole thing, which would kill the app.
                    // So we will use a fixed size buffer and manually look for lines inside it.
                    int    _bufferSize = 16384;
                    char[] readBuffer  = new char[_bufferSize];

                    StringBuilder workingBuffer = new StringBuilder(); // where we will store the left over stuff after we split the read buffer into lines

                    // read into the buffer
                    long charsRead = streamReader.Read(readBuffer, 0, _bufferSize);
                    totalCharsRead += charsRead;

                    while (charsRead > 0)
                    {
                        if (worker.CancellationPending)
                        {
                            wasCancelled = true;
                            //display cancellation message
                            CancelProgressDelegate canceller = new CancelProgressDelegate(CancelProgressText);
                            dispatcher.BeginInvoke(canceller, _rowsProcessed);
                            return(true);
                        }

                        // put the stuff we just read from the file into our working buffer
                        workingBuffer.Append(readBuffer);

                        // slice the workingBuffer into lines
                        string[] linesArray = workingBuffer.ToString().Split('\n');

                        // process all the lines EXCEPT THE LAST ONE in the lines array (the last one is likely to be incomplete)
                        for (int i = 0; i < (linesArray.Length - 1); i++)
                        {
                            string line = linesArray[i];
                            // the line should have the same number of columns as the ColumnCollection, if not then up the jagged lines count, and skip processing
                            string[] lineColumns = line.Split(',');


                            // if we get a jagged result here (i.e. length of columns does not match the headers) then try a split using quote delimited data
                            if (lineColumns.Length != ColumnCollection.Count)
                            {
                                // thanks to http://stackoverflow.com/questions/3776458/split-a-comma-separated-string-with-both-quoted-and-unquoted-strings
                                // for this bit of regex
                                Regex csvSplit = new Regex("(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)", RegexOptions.Compiled);

                                int jag = 0;
                                lineColumns = new string[csvSplit.Matches(line).Count];
                                foreach (Match match in csvSplit.Matches(line))
                                {
                                    lineColumns[jag] = match.Value.TrimStart(',');
                                    jag++;
                                }
                            }

                            // if we're still jagged then we can't do much other than skip processing this line and increment the jagged counter
                            if (lineColumns.Length != ColumnCollection.Count)
                            {
                                _jaggedLines++;
                            }
                            else
                            {
                                // get the columns for crypting using the inputFields, since this is a sorted list we always get the indexes from aphabetically ordered keys
                                SortedList <string, string> hashNameValueCollection = new SortedList <string, string>();

                                // first column is the digest
                                foreach (string key in inputFields.Keys)
                                {
                                    string theData = lineColumns[inputFields[key]];

                                    // we always process the one they selected as NHSNumber ..
                                    if (_performNHSNumberValidation)
                                    {
                                        string nhskey = inputHeadings[indexOfNHSNumber - 1];
                                        if (nhskey == key)
                                        {
                                            theData = crypto.ProcessNHSNumber(theData);
                                        }
                                    }
                                    hashNameValueCollection.Add(key, theData);
                                }
                                string digest   = crypto.GetDigest(hashNameValueCollection);
                                string validNHS = "";
                                lineToWrite = digest + ",";

                                // output the rest of the columns in the output list
                                foreach (int key in outputFields.Keys) // keys in the output are indexes (opposite to input SortedList)
                                {
                                    // Look for column heading that is a date..
                                    if (_processDateColumns.Contains(outputFields[key]))
                                    {
                                        lineToWrite += crypto.RoundDownDate(lineColumns[key]) + ",";
                                    }
                                    else
                                    {
                                        lineToWrite += lineColumns[key] + ",";
                                    }
                                }

                                // last column is the NHS Validation (if requested)
                                if (_performNHSNumberValidation)
                                {
                                    // find the NHSNumber in the list of input columns and validate it
                                    string key = inputHeadings[indexOfNHSNumber - 1];
                                    {
                                        string trimmedNHSNumber = lineColumns[indexOfNHSNumber - 1].Trim();
                                        // trimmed data is length < 1 so we call this missing NHS Number
                                        if (trimmedNHSNumber.Length < 1)
                                        {
                                            validNHS = "-1";
                                            _missingNHSNumCount++;
                                        }
                                        else
                                        {
                                            // we have data for the NHS field, is it valid?
                                            string cleanedNHSNumber = crypto.ProcessNHSNumber(trimmedNHSNumber);
                                            if (NHSNumberValidator.IsValidNHSNumber(cleanedNHSNumber))
                                            {
                                                validNHS = "1";
                                                _validNHSNumCount++;
                                            }
                                            else
                                            {
                                                validNHS = "0";
                                                _inValidNHSNumCount++;
                                            }
                                        }
                                        lineToWrite += validNHS + ",";
                                    }
                                }

                                // we're done writing the output line now. Strip trailing comma.
                                lineToWrite = lineToWrite.Substring(0, lineToWrite.Length - 1);
                                // some files have a double line break at the end of the lines, remove this.
                                lineToWrite = lineToWrite.Replace(Environment.NewLine, "").Replace("\r\n", "").Replace("\n", "").Replace("\r", "");
                                streamWriter.WriteLine(lineToWrite);
                            }
                        }
                        _rowsProcessed += linesArray.Length - 1;

                        // set the working buffer to be the last line, so the next pass can concatonate
                        string lastLine = linesArray[linesArray.Length - 1];
                        workingBuffer = new StringBuilder(lastLine);

                        UpdateProgressDelegate update = new UpdateProgressDelegate(UpdateProgressText);
                        dispatcher.BeginInvoke(update, totalCharsRead, _inputFileStreamLength, _rowsProcessed, _validNHSNumCount, _inValidNHSNumCount, _missingNHSNumCount);

                        // empty the readbuffer, or the last read will only partially fill it, and we'll have some old data in the tail
                        readBuffer = new char[_bufferSize];
                        // read the next lot
                        charsRead       = streamReader.Read(readBuffer, 0, _bufferSize);
                        totalCharsRead += charsRead;
                    }
                }
            }
            return(false);
        }