We are archiving a bunch of InfoPath [IP] documents. The data are going to be stored in MS Access 2010 (with attachments in the file system, storing references to them in the Access DB).
I found one VBA solution to extract the file that the IP form contains, but it doesn't function. (http://www.infopathdev.com/forums/p/10182/36240.aspx)
I have found many .NET solutions, but have had no luck converting them to VBA.
How can I take the file name & file contents contained in an IP Attachment node, and (using Access's VBA) create a real file, stored in the file system?
InfoPath attachments are base64 encoded. The encoding can be "unpacked" with
' The MSXML2.DOMDocument class has methods to
' convert a base64—encoded string to a byte array.
Private Function DecodeBase64(ByVal strData As String) As Byte()
Dim obj_XML As MSXML2.DOMDocument
Dim objNode As MSXML2.IXMLDOMElement
' Getting help from MSXML
Set obj_XML = New MSXML2.DOMDocument
Set objNode = obj_XML.createElement("b64")
objNode.DataType = "bin.base64"
objNode.Text = strData
' Return the value
DecodeBase64 = objNode.nodeTypedValue
Set objNode = Nothing
Set obj_XML = Nothing
End Function
The byte arrays' first 16 bytes are a useless header.
The next 4 bytes are a little-endian unsigned integer, of the actual size of the file. This information is unnecessary, too.
The next 4 bytes are a little-endian unsigned integer, of the number of characters in the FileName. The FileName is in UniCode, so it has 2 bytes / char. Multiply the number of the FileName size by 2, therefore. The name will have nulls at the end that need to be removed.
Finally, the remainder past that point is the file.
I decided to create a helper class to split the byte array of the attachment. My class takes a byte array, and a number. the input array will be split into 2 properties, representing the top and bottom halves. That number entered is 1) the number of bytes for the bottom array, and 2) the index of the first byte of the entered array to put into the top part.
I initially fed it the whole attachment, and added it to the object, splitting it at 23. This put the header and the file-size bytes and the filename size, and put them into the bottom array, and the filename and the file contents, and put it into the top.
I made a reference to those two arrays (to persist them), then fet the bottom array into the object, splitting at 19. I discard the bottom, having the filename size in the top.
After converting that to a Long, I fet the upper part into the object, splitting it at the value of FileNameSize times 2. Thus the filename is in the bottom, and the file is in the top.
Using 2 user-defined types, I line up the 4 bytes of the FileName size into 4 contiguous bytes in one, and treat the other UDT as a single long. Using the LSet statement, I copy the 4 contiguous bytes of the 1st UDT to the 4 contiguous bytes of the 2nd UDT. This converts the bytes to a long.
VBA automatically, implicitly converts byte arrays to strings, if you set a string equal to a byte array of UniCode bytes.
Finally, the upper array is copied to a file, using Put.
The class:
Private pLow() As Byte
Private pHigh() As Byte
Private src() As Byte
Private pt As Long
Public Property Get Low() As Byte(): Low = pLow: End Property
Public Property Get High() As Byte(): High = pHigh: End Property
Private Function outOfBounds() As Boolean
Dim msg As String
' Check the bounds
If pt < 0 Then _
msg = "Division point cannot be less than zero"
If pt > (UBound(src) + 1) Then ' When = UBound + 1, copy whole array into pLo
msg = "‘point’ is greater the the size of the array."
End If
If msg <> "" Then
outOfBounds = True
src = Null
Err.Raise vbObjectError + 6, msg
End If
End Function
' point is the index of the 1st element to be copied into pHi
Public Sub Load(SrcArr() As Byte, point As Long)
src = SrcArr ' grant class-wide access.
pt = point ' grant class-wide access.
If outOfBounds() Then Exit Sub
' Create new arrays and assign to private fields
Dim L() As Byte
Dim H() As Byte
Dim hiUB As Long
hiUB = UBound(src) - point
If point <> 0 Then ' <————<< If ‘point’ is 0, then this is just going to be a copy of
ReDim L(point - 1) ' the whole array into pHi; don’t initialize pLo.
End If
If point <> (UBound(src) + 1) Then ' <————<< If it is the SIZE of the array (UBound+1), then this is
ReDim H(hiUB) ' just going to be a copy of the whole array into pLo, so
End If ' there would be no need to initialize pHi.
' Do the two copies
If point <> 0 Then _
MoveMemory L(0), src(0), point ' ‘point’ is the 0-based 1st element to copy into pHi. So it
' also serves as the 1-based copy SIZE, for copying into pLo.
If point <> (UBound(src) + 1) Then _
MoveMemory H(0), src(point), (hiUB + 1)
pLow = L
pHigh = H
End Sub
The processing:
Public Sub processAttachment(dataIn As String, Optional path As String)
On Error GoTo Er
' After development, remove this:
If IsMissing(path) Or path = "" Then path = "had a default here"
Dim fNum As Integer ' File number, for file communication.
Dim fName As String
Dim fNamSz As Long
Dim b_Tmp() As Byte
Dim btArr() As Byte
btArr = DecodeBase64(dataIn) ' <————<<< dataIn is a base64-encoded string. Convert it to a byte array.
Dim cAS As New clsArraySplitter ' Instantiate the class for getting array sections.
cAS.Load btArr, 24 ' Separate the data at the beginning of btArr (whose size is set), from the
btArr = cAS.High ' rest of the data (whose sizes will be different for each attachment).
' Header (16 bytes, 0-15) + 2, 4-byte long int.s = 16 + 4 + 4 = 24.
' Set the dymaically-sized portion of the data (fName & the file) aside, for now.
cAS.Load cAS.Low, 16 ' Dump Hdr; puts part to be dumped in .Low, 2 longs in .High
' Now .Low has header to be dumped; just ignore it,
' .High has fSize & fNameSize (8 bytes, total).
cAS.Load cAS.High, 4 ' Now .Low has fSize (4 bytes; I don't need this info),
' .High has fNameSize (4 bytes).
fNamSz = ByteArrayToLong(cAS.High) ' Get FileName character count
fNamSz = fNamSz * 2 ' UniCode has 2-bytes per character
' Now, refocus on the array having fname & file.
' Separate into 2 parts, the file name, and the file.
cAS.Load btArr, fNamSz ' Now .Low has the fName,
' .High has the file.
' Get fName, then trim null(s) off the right end.
fName = Trim(cAS.Low) ' VB handles this Byte array to string conversion.
Dim pos As Integer
pos = InStr(fName, Chr$(0)) ' No matter how many, pos points at the 1st one.
If pos > 0 Then _
fName = Left$(fName, pos - 1)
' Open output byte array to a file, then close the file.
' I need to check for the existence of the file, and add '(n)' to the filename if it already exists.
' Since attachments are not stored in the XML by name, InfoPath can store attachments with exactly the same name
' (with or w/o different contents) any # of times. Since I’m saving to the file system, I can’t do that.
fName = UniqueFileName(path, fName)
path = path & fName
fNum = FreeFile
Open path For Binary Access Write As fNum
Put fNum, , cAS.High
Rs: Close fNum ' This ‘Close’ is put here, at the resume point, so that it is sure to be closed
Exit Sub
Er: MsgBox "Error, """ & Err.Description & ","" in ""processAttachment()."""
Resume Rs
End Sub
Hope that all formats right . . .
Related
I have been trying to get the path to a linked table. I am looping thru the tables. it works one the first loop but not on the 2nd loop. it returns "".
Ive tried several different ways, calling the table by name or by number. the code originally comes from Neville Turbit. Neville's code calls the table by name, but I could not get that to work.
Public Function GetLinkedDBName(TableName As String)
Dim tblTable As TableDef
Dim strReturn As String
Dim i As Integer
On Error GoTo Error_NoTable ' Handles table not found
'---------------------------------------------------------------
'
i = 0
On Error GoTo Error_GetLinkedDBName ' Normal error handling
For Each tblTable In db.TableDefs
If tblTable.Name = TableName Then
strReturn = tblTable.Connect
strReturn = db.TableDefs(i).Connect
Exit For
End If
i = i + 1
Next tblTable
You don't need a loop:
Public Function GetLinkedDBName(TableName As String) As String
Dim strReturn As String
On Error Resume Next ' Handles table not found
strReturn = CurrentDb.TableDefs(TableName).Connect
GetLinkedDBName = strReturn
End Function
This is my modification from Gustav's.
CurrentDb.TableDefs(TableName).Connect command will returns a string like this:
"MS Access;PWD=p455w0rd;DATABASE=D:\Database\MyDatabase.accdb"
The string above contains 3 information and parted by ";" char.
You need to split this information and iterate through it to get specific one which contain database path.
I am not sure if different version of ms access will return exact elements and with exact order of information in return string. So i compare the first 9 character with "DATABASE=" to get the index of array returns by Split command and get path name from it.
Public Function getLinkedDBName(TableName As String) As String
Dim infos, info, i As Integer 'infos and info declared as Variant
i = -1
On Error Resume Next ' Handles table not found
'split into infos array
infos = Split(CurrentDb.TableDefs(TableName).Connect, ";")
'iterate through infos to get index of array (i)
For Each info In infos
i = i + 1
If StrComp(Left(info, 9), "DATABASE=") = 0 Then Exit For
Next info
'get path name from array value and return the path name
getLinkedDBName = Right(infos(i), Len(infos(i)) - 9)
End Function
So I seem to be able to save BLOB files from Access okay using the code below (which I found while searching how to export a BLOB). But it doesn't seem to be saving a valid .png file. When I try to open the file from disk I get the error "Windows Photo Viewer can't open this picture because the file is appears to be damaged, corrupted, or is too large. I know it's not too large because it's only 1.19MB. Is there a special way you have to write the BLOB file to disk that makes it readable or is there something else that I'm missing?
-EDIT-
Taking Gord's advice, I have got the code below using an ADODB.Stream. Unfortunately, I'm still running into the same problem where the file this writes to does not open in windows picture viewer. I'm wondering if this is because of the file extension I am giving it, but I've tried writing to a .JPG file (the default snipping tool save option which is where I expect the pictures to be input from) as well as .png (the file type I want) and .gif. Any ideas would be helpful as to how to solve this problem.
Public Sub TestBlobStream()
Dim mStream As New ADODB.Stream
Dim rs As RecordSet
Set rs = dbLocal.OpenRecordset("BlobTest")
Set mStream = New ADODB.Stream
mStream.Type = adTypeBinary
mStream.Open
mStream.Write rs("testBlob")
mStream.SetEOS
mStream.SaveToFile "D:\Target\TestPic.png", adSaveCreateOverWrite
mStream.Close
End Sub
-END EDIT-
Code referenced in original part of question:
Public Sub TestBlob()
Dim rs As RecordSet
Set rs = dbLocal.OpenRecordset("BlobTest")
DBug WriteBLOB(rs, "testBlob", "D:\Target\TestPic.png")
Set rs = Nothing
End Sub
Function WriteBLOB(T As DAO.RecordSet, sField As String, Destination As String)
Dim NumBlocks As Long, DestFile As Long, i As Long
Dim FileLength As Long, LeftOver As Long
Dim FileData As String
Dim RetVal As Variant
' Get the size of the field.
FileLength = T(sField).FieldSize()
If FileLength = 0 Then
WriteBLOB = 0
Exit Function
End If
' Calculate number of blocks to write and leftover bytes.
NumBlocks = FileLength \ BlockSize
LeftOver = FileLength Mod BlockSize
' Remove any existing destination file.
DestFile = FreeFile
Open Destination For Output As DestFile
Close DestFile
' Open the destination file.
Open Destination For Binary As DestFile
' SysCmd is used to manipulate the status bar meter.
RetVal = SysCmd(acSysCmdInitMeter, _
"Writing BLOB", FileLength / 1000)
' Write the leftover data to the output file.
FileData = T(sField).GetChunk(0, LeftOver)
Put DestFile, , FileData
' Update the status bar meter.
RetVal = SysCmd(acSysCmdUpdateMeter, LeftOver / 1000)
' Write the remaining blocks of data to the output file.
For i = 1 To NumBlocks
' Reads a chunk and writes it to output file.
FileData = T(sField).GetChunk((i - 1) * BlockSize + LeftOver, BlockSize)
Put DestFile, , FileData
RetVal = SysCmd(acSysCmdUpdateMeter, _
((i - 1) * BlockSize + LeftOver) / 1000)
Next i
' Terminates function
RetVal = SysCmd(acSysCmdRemoveMeter)
Close DestFile
WriteBLOB = FileLength
Exit Function
End Function
I have a vb6 project. It was developed by senior. Now I want to change the existing code. I am new for vb6. The database file like ini format. Actually he worked with access database. I want to create some tables in this database. Please give any idea to open ini file in access database or any idea to open ini file.
Oh my, this is old stuff:
Jose 's VB Tips & Tricks
Using Initialization Files
To paraphrase the great American author Mark Twain, reports of the demise
of .ini files have been greatly exaggerated.
While Microsoft has proclaimed the registry to be the proper storehouse of
initialization information, .ini files still have their uses. Among the
advantages of .ini files are:
The files are easily "human readable" using any simple text editor
such as Notepad.
The API code for working with .ini files is considerably simpler than
the equivalent registry APIs.
Files can be easily opened over a network with nothing more than a
basic redirector installed on either end.
Installation of an .ini file is as simple as copying the file to the
Windows directory.
Windows provides a variety of APIs for working with .ini files, including
the GetProfileXXX and WriteProfileXXX functions dedicated to working with
win.ini and the following functions for reading and writing private
initialization files:
GetPrivateProfileString
Read a string from an .ini file.
GetPrivateProfileInt
Read an integer from an .ini file.
WritePrivateProfileString
Write a string to an .ini file.
WritePrivateProfileInt
Write an integer to an .ini file.
Given, however, that all of the data in .ini files is plain old text,
there 's really no need to separately code the xxxInt versions of these
functions. Converting a string to an Int in VB is simple enough using the
CInt() or Val() function, so only the GetPrivateProfileString and
WritePrivateProfileString functions are needed.
Both of these are simple API calls. There is one exception case when
reading .ini files that return a C string with multiple values separated by
Nulls. To parse that string, I've included the MultiCStringToStringArray
function.
Before continuing, you 'll need to add two Declares to the declarations
section of a module somewhere. As a matter of habit, I alias Win32 APIs
with "w32_" so that I can write a VB wrapper function and give it the name
of the API function.
Here 's the declarations section:
Option Explicit
Private Declare Function w32_GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" ( _
ByVal lpAppName As String, _
ByVal lpKeyName As String, _
ByVal lpDefault As String, _
ByVal lpReturnedString As String, _
ByVal nSize As Long, _
ByVal lpFileName As String) As Long
Private Declare Function w32_WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" ( _
ByVal lpApplicationName As String, _
ByVal lpKeyName As Any, _
ByVal lpString As Any, _
ByVal lpFileName As String) As Long
Here 's the code for GetPrivateProfileString:
Public Function GetPrivateProfileString( _
psAppName As String, _
psKeyName As String, _
Optional pvsDefault As Variant, _
Optional pvsFileName As Variant) As String
'********************
' Purpose: Get a string from a private .ini file
' Parameters:
' (Input)
' psApplicationName - the Application name
' psKeyName - the key (section) name
' pvsDefault - Default value if key not found (optional)
' pvsFileName - the name of the .ini file
' Returns: The requested value
' Notes:
' If no value is provided for pvsDefault, a zero-length string is used
' The file path defaults to the windows directory if not fully qualified
' If pvsFileName is omitted, win.ini is used
' If vbNullString is passed for psKeyName, the entire section is returned in
' the form of a multi-c-string. Use MultiCStringToStringArray to parse it after appending the
' second null terminator that this function strips. Note that the value returned is all the
' key names and DOES NOT include all the values. This can be used to setup multiple calls for
' the values ala the Reg enumeration functions.
'********************
' call params
Dim lpAppName As String
Dim lpKeyName As String
Dim lpDefault As String
Dim lpReturnedString As String
Dim nSize As Long
Dim lpFileName As String
' results
Dim lResult As Long
Dim sResult As String
sResult = ""
' setup API call params
nSize = 256
lpReturnedString = Space$(nSize)
lpAppName = psAppName
lpKeyName = psKeyName
' check for value in file name
If Not IsMissing(pvsFileName) Then
lpFileName = CStr(pvsFileName)
Else
lpFileName = "win.ini"
End If
' check for value in optional pvsDefault
If Not IsMissing(pvsDefault) Then
lpDefault = CStr(pvsDefault)
Else
lpDefault = ""
End If
' call
' setup loop to retry if result string too short
Do
lResult = w32_GetPrivateProfileString( _
lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, lpFileName)
' Note: See docs for GetPrivateProfileString API
' the function returns nSize - 1 if a key name is provided but the buffer is too small
' the function returns nSize - 2 if no key name is provided and the buffer is too small
' we test for those specific cases - this method is a bit of hack, but it works.
' the result is that the buffer must be at least three characters longer than the
' longest string(s)
If (lResult = nSize - 1) Or (lResult = nSize - 2) Then
nSize = nSize * 2
lpReturnedString = Space$(nSize)
Else
sResult = Left$(lpReturnedString, lResult)
Exit Do
End If
Loop
GetPrivateProfileString = sResult
End Function
Here 's WritePrivateProfileString:
Public Function WritePrivateProfileString( _
psApplicationName As String, _
psKeyName As String, _
psValue As String, _
psFileName As String) As Boolean
'********************
' Purpose: Write a string to an ini file
' Parameters: (Input Only)
' psApplicationName - the ini section name
' psKeyName - the ini key name
' psValue - the value to write to the key
' psFileName - the ini file name
' Returns: True if successful
' Notes:
' Path defaults to windows directory if the file name
' is not fully qualified
'********************
Dim lResult As Long
Dim fRV As Boolean
lResult = w32_WritePrivateProfileString( _
psApplicationName, _
psKeyName, _
psValue, _
psFileName)
If lResult <> 0 Then
fRV = True
Else
fRV = False
End If
WritePrivateProfileString = fRV
End Function
And finally, here's MultiCStringToStringArray:
Public Sub MultiCStringToStringArray(psMultiCString As String, psaStrings() As String)
'Created: Joe Garrick 01/06/97 9:28 AM
'********************
' Purpose: Convert a multi-string C string to an array of strings
' Parameters:
' (Input)
' psMultiCString - the multiple C string
' (Output)
' psaStrings - returned array of strings
' Notes:
' The original array should be empty and ReDim-able
'********************
Dim iNullPos As Integer
Dim iPrevPos As Integer
Dim iIdx As Integer
' initialize array, setting first element to a zero-length string
iIdx = 0
ReDim psaStrings(0 To iIdx + 1)
psaStrings(iIdx + 1) = ""
Do
' find null char
iNullPos = InStr(iPrevPos + 1, psMultiCString, vbNullChar)
' double null encountered if next pos is old pos + 1
If iNullPos > iPrevPos + 1 Then
' assing to the string array
psaStrings(iIdx) = Mid$(psMultiCString, (iPrevPos + 1), ((iNullPos - 1) - iPrevPos))
iIdx = iIdx + 1
ReDim Preserve psaStrings(0 To iIdx)
iPrevPos = iNullPos
Else
' double null found, remove last (empty) element and exit
ReDim Preserve psaStrings(0 To iIdx - 1)
Exit Do
End If
Loop
End Sub
that 's all there is to coding .ini files.
Notes
Check the SDK documentation for the specifics of behavior of these
functions.
If you send a zero-length string to the write function, the key is
removed.
If you attempt to write a value for a key that does not exist or a
section that does not exist, the key or section will be created.
Despite Microsoft's portrayal of the registry as the central
repository for configuration information under Win95, win.ini and
system.ini are still used, so exercise caution when working with these
files (in other words, make a backup before you experiment).
GetPrivateProfileString returns the requested data, but
WritePrivateProfileString returns a boolean indicating success or
failure. While GetPrivateProfileString is highly reliable, it could
easily be modified to return a Boolean or some other type of status
code indicating the result.
If you use GetPrivateProfileString to return an entire section,
remember to add an additional null (string & vbNullChar will do it)
before calling MultiCStringToStringArray since that function expects
two nulls to terminate the string. Also, keep in mind that only the
key names are returned, not the values.
Return to Top of Page [Return to top of page]
| Home | Jose's World of Visual Basic | Jose's VB Tips & Tricks |
| © 1997 Joe Garrick | Info Center | [E-mail]jgarrick#citilink.com |
I'm trying to make it possible for the data stored in a MSSQL database to be encrypted/decrypted in both Access 2013 as well as ColdFusion. The Access database uses vba to sync data to the SQL database and I've found a few possible solutions for encryption but can't seem to get the results to match the same thing encrypted in ColdFusion.
www.ebcrypt.com appears to be the easiest but when I encrypt with either Blowfish, RIJNDAEL or any of the other methods, the results are not the same as what I encrypt in ColdFusion.
I decided to try to use the native CryptoAPI but the same thing happens when I try to match what vba is doing in ColdFusion I keep getting different results.
I wonder if either the vba or ColdFusion methods I'm using are taking the key I'm passing in and transforming it so it no longer matches. I've tried setting keys manually and even generating it with ColdFusion and then setting it in the vba code to match with no luck.
ColdFusion code trying to use RC4:
<cfset test_key = "ZXNlmehY30y3ophXVJ0EJw==">
<cfset encryptedString = Encrypt("CF String",test_key, "RC4")>
<cfoutput>
Encrypted String: #encryptedString#<br />
Encryption Key: #test_key#
</cfoutput>
VBA Code with the same settings: (clsCryptoFilterBox code is here)
NOTE: It appears that this defaults to RC4, which is why I'm using that in ColdFusion above.
Dim encrypted As clsCryptoFilterBox
Set encrypted = New clsCryptoFilterBox
encrypted.Password = "ZXNlmehY30y3ophXVJ0EJw=="
encrypted.InBuffer = "CF String"
encrypted.Encrypt
MsgBox ("Encrypted: " & encrypted.OutBuffer)
EDIT: Ok, more info. I found that ColdFusion needed the key in base64 even though the variable test_key should have worked but apparently the output of a base64 encoded string is not the same as other text encoded into base64.
EDIT 2: I got it working using the Blowfish algorithm found in the file on this website.
Here is my working CF code:
<cfset test_key = toBase64("1234567812345678")>
<cfset encryptedString = Encrypt("CF String", test_key, "RC4", "HEX")>
<cfoutput>
Encrypted String: #encryptedString#<br />
Encryption Key: #test_key#
</cfoutput>
Which outputs:
Encrypted String: F8B519877DC3B7C997
Encryption Key: MTIzNDU2NzgxMjM0NTY3OA==
I had to modify the code in VBA to pad using PKCS7 but once I did that, I was able to verify that it was working correctly. If anyone is interested I could post my changes to the VBA code where I modified the padding as well as added a check on decryption to verify the data via the padding.
I found a decent Blowfish algorithm packaged in the test app found on this download site that actually works with some modifications.
It was using spaces to pad the input text which is not what ColdFusion was doing, so this was making the encrypted string turn out different. The standard encryption that CF does pads with bytes that are all the same and are set to the number of padding bytes being used.
New EncryptString() function:
Public Function EncryptString(ByVal tString As String, Optional ConvertToHEX As Boolean) As String
Dim ReturnString As String, PartialString As String * 8
Dim tPaddingByte As String
Dim tStrLen As Integer
Dim tBlocks As Integer
Dim tBlockPos As Integer
tStrLen = Len(tString)
'Divide the length of the string by the size of each block and round up
tBlocks = (-Int(-tStrLen / 8))
tBlockPos = 1
Do While tString <> ""
'Check that we are not on the last block
If tBlockPos <> tBlocks Then
'Not on the last block so the string should be over 8 bytes, no need to pad
PartialString = Left$(tString, 8)
Else
'Last block, we need to pad
'Check to see if the last block is 8 bytes so we can create a new block
If Len(tString) = 8 Then
'Block is 8 bytes so add an extra block of padding
tString = tString & String(8, Chr(8))
tPaddingByte = " " 'Not really necessary, just keeps the String() function below happy
Else
'Set the value of the padding byte to the number of padding bytes
tPaddingByte = Chr(8 - Len(tString))
End If
PartialString = Left$(tString & String(8, tPaddingByte), 8)
End If
ReturnString = ReturnString & Encrypt(PartialString)
tString = Mid$(tString, 9)
tBlockPos = tBlockPos + 1
Loop
If ConvertToHEX = True Then
EncryptString = ToHEX(ReturnString)
Else
EncryptString = ReturnString
End If
End Function
Since the padding is not just spaces, it needs to be removed on decryption but there is an easy way to do it that also makes this whole process even better. You read the last byte, and then verify the other padding bytes with it.
Public Function DecryptString(ByVal tString As String, Optional ConvertFromHEX As Boolean) As String
Dim ReturnString As String, PartialString As String * 8
Dim tPos As Integer
Dim tPadCount As Integer
If ConvertFromHEX = True Then
tString = HexToString(tString)
End If
Do While tString <> ""
PartialString = Left$(tString, 8)
ReturnString = ReturnString & Decrypt(PartialString)
tString = Mid$(tString, 9)
Loop
'Check the last byte and verify the padding and then remove it
tPadCount = ToHEX(Right(ReturnString, 1))
If tPadCount < 8 Or tPadCount > 1 Then
'Get all the padding bytes and verify them
Dim tPaddingBytes As String
tPaddingBytes = Right(ReturnString, tPadCount)
Dim i As Integer
For i = 1 To tPadCount
If Not tPadCount = Int(ToHEX(Left(tPaddingBytes, 1))) Then
MsgBox "Error while decrypting: Padding byte incorrect (" & tPadCount & ")"
GoTo Done
End If
Next i
ReturnString = Left(ReturnString, Len(ReturnString) - tPadCount)
Else
MsgBox "Error while decrypting: Last byte incorrect (" & tPadCount & ")"
End If
Done:
DecryptString = ReturnString
End Function
I was able to export the class module and can import it into any other possible projects that may need basic encryption. There is a Rijndael class that appears to be working but in a non-standard way as well that I may get around to fixing later, but for now this is what I was looking for.
I have a .CSV File with 5 values in a row , i want to modify the file in a way i should add one more value in the Beginning/End/Middle of the row.
How to add a new row with a set of values in the .CSV File?
How to do this in a simple way?
There is no magic way to insert things into the middle of a stream file (such as any text file including CSV files).
So this means you need to read the old file and modify it as you go writing a new file out.
There are many ways to do this though:
Read the input file into memory as a blob and work on it there then write out the modified data.
Read/write it with changes line by line.
Use Jet Text IISAM, Log Parser's COM API, etc. which allow SQL and SQL-like operations on text data in tabular formats such as CSV.
The simplest and most general way is line by line read/modify/write. This can be slower than the "blob" approach for small to middling files but doesn't risk the headaches that may result when a large file must be processed.
For very large files this can be optimized by reading, parsing, modifying, then writing in "chunks" to minimize I/O costs. But this can also be more complex to program correctly.
This piece of code may help , this is not an answer but it will help
Dim line As String
Dim arrayOfElements() As String
Dim linenumber As Integer
Dim i As Integer
Dim opLine As String
Dim fso As New FileSystemObject
Dim ts As TextStream
line = ""
Open strPath For Input As #1 ' Open file for input
Do While Not EOF(1) ' Loop until end of file
linenumber = linenumber + 1
Line Input #1, line
arrayOfElements = Split(line, "|")
If Not linenumber = 1 Then
If UBound(arrayOfElements) = 2 Then
line = line & "|x|y"
opLine = opLine & line & vbCrLf
End If
Else
line = line & "|col4|col5"
opLine = opLine & line & vbCrLf
End If
Loop
Close #1 ' Close file.
Set ts = fso.CreateTextFile(strPath, True)
ts.WriteLine (opLine)
ts.Close
fso need to be closed!
Set fso = Nothing