Adding the Use License to the Compound File

After you have added a new issuance license to a file, you can acquire a use license for a requesting user and store it right in the document. That way, the user can view the document immediately, without making an additional call to a server for a use license.

The use license is stored as a new stream within the \009DRMTransform storage object that holds the signed issuance license. The new use license stream is given a unique name, beginning with "EUL-", so that it will not conflict with any other streams within the compound file. The data after "EUL-" is not particularly important, as long as it is unique and 27 or fewer WCHARs long (32 WCHARs – 1 for a terminating null WCHAR, – 4 for "EUL-"). In the following example, a random GUID is generated by using the NewGuid method of the .NET Framework Guid object, and then it is compressed by base32-encoding it.

The following example, from Cdoclib.cpp, shows adding a use license to a compound file.

AddEndUserLicense(WCHAR* wszEUL, 
              WCHAR*wszbase64ConsumerName,
              WCHAR*wszRmhFilePath, 
              WCHAR* EULClassID) // Unique ID created by application.
{
   int HeaderLen = 0;
   int EntryCount = 0;
   int EntryLength = 0;
   int RefComponentCount = 0;
   int RefComponentType = 0;
   int RefComponentLen = 0;
   int RefComponentPad = 0;
   int DataSpaceNameLen = 0;
   int DataSpaceNamePad = 0;
   int TotalLength = 0;

   LPWSTR RefComponent = NULL;
   LPWSTR DataSpaceName = NULL;

   WCHAR StorageName_DataSpaces[12]    =    L"*DataSpaces";
   WCHAR StorageName_DataSpaceInfo[14] =    L"DataSpaceInfo";
   WCHAR StorageName_TransformInfo[14] =    L"TransformInfo";
   WCHAR StorageName_DRMTransform[14]  =    L"*DRMTransform";
   WCHAR StreamName_DRMViewerContent[18] =  L"*DRMViewerContent";
   WCHAR StreamName_Version[8]         =    L"Version";
   WCHAR StreamName_DataSpaceMap[13]   =    L"DataSpaceMap";
   WCHAR StreamName_DRMDataSpace[14]   =    L"*DRMDataSpace";
   WCHAR StreamName_Primary[9]         =    L"*Primary";
 
  // Insert special characters into storage/stream names.
   short char_nine=9;
   short char_six=6;
   memcpy(StorageName_DataSpaces, &char_six, 2);
   memcpy(StorageName_DRMTransform, &char_nine, 2);
   memcpy(StreamName_DRMDataSpace, &char_nine, 2);
   memcpy(StreamName_Primary, &char_six, 2);

   // Storages and streams.
   IStorage *pStorage = NULL;
   IStorage *pDataSpaceStorage = NULL;
   IStorage *pTransformInfoStorage = NULL;
   IStorage *pDRMTransformStorage = NULL;
   IStream  *pStream = NULL;

   HRESULT hResult = NULL;
   ULONG bytesWritten = 0;
   BYTE *EncryptedBuffer = NULL;
   DWORD dwBufferSize = 0;
   BYTE *dataspacemap = NULL;
   LPSTR wszEUL64 = NULL;
   BYTE *eul_stream = NULL;
   LPSTR szRightsLabel = NULL;
   BYTE *drm_transform = NULL;

   VERSIONSTAMP version;
   version.ReaderVersionMajor  = 1;
   version.ReaderVersionMinor  = 0;
   version.UpdaterVersionMajor = 1;
   version.UpdaterVersionMinor = 0;
   version.WriterVersionMajor  = 1;
   version.WriterVersionMinor  = 0;


   // Open the previously created compound file.
   hResult = StgOpenStorageEx( 
              wszRmhFilePath,           // File name
              STGM_READWRITE|           // File access
                 STGM_SHARE_EXCLUSIVE, 
              STGFMT_STORAGE,           // Compound file
              0,                        // Required
              NULL,                     // Required
              0,                        // Required
              IID_IStorage,             // IStorage IID
              (void **)&pStorage);      // IStorage pointer

   // Navigate to \009DRMTransform storage space
   // to add a new stream to hold the use license.
   memcpy(StorageName_DataSpaces, &char_six,2);
   hResult = pStorage->OpenStorage(
              StorageName_DataSpaces,
              NULL,
              STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
              NULL,
              0,
              &pDataSpaceStorage);

   hResult = pDataSpaceStorage->OpenStorage( 
              StorageName_TransformInfo,
              NULL,
              STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
              NULL,
              0,
              &pTransformInfoStorage);

   memcpy(StorageName_DRMTransform, &char_nine,2);
   hResult = pTransformInfoStorage->OpenStorage(
              StorageName_DRMTransform,
              NULL,
              STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
              NULL,
              0,
              &pDRMTransformStorage);

   // Create a new, uniquely named stream to hold 
   // the use license.
   hResult = pDRMTransformStorage->CreateStream( 
              EULClassID,               // Required name
              STGM_READWRITE |          // File access
                 STGM_SHARE_EXCLUSIVE, 
              0,                        // Required
              0,                        // Required
              &pStream);                // IStream pointer

   // base64-encode the EUL.
   LPWSTR wszEUL64 = wszEUL;
   int b64usernamelen = (int)wcslen(wcsbase64ConsumerName);
   int licenselength = (int)wcslen(wszEUL64);

   int dwordalign = PaddingLength(b64usernamelen,sizeof(DWORD));
   int eulstreamLength = 8 + b64usernamelen + dwordalign;

   wszEUL64 = (CHAR *)HeapAlloc(
              GetProcessHeap(), 
              HEAP_ZERO_MEMORY, 
              wcslen(wszEUL64)+1);
   if ( NULL == wszEUL64 )
   {
      printf("Error (%s): E_OUTOFMEMORY\n", "HeapAlloc");
      goto e_Exit;
   }
   StringCchPrintf(wszEUL64, 
                   wcslen(wszEUL64)+1, 
                   "%S", 
                   wszEUL64);


   // Copy the data to a buffer.
   eul_stream = (BYTE *)HeapAlloc(
              GetProcessHeap(),
              0,
              eulstreamLength + licenselength + 4 +
                 PaddingLength(licenselength,sizeof(DWORD)));
   
   if ( NULL == eul_stream )
   {
      printf("Error (%s): E_OUTOFMEMORY\n", "HeapAlloc");
      goto e_Exit;
   }
   ZeroMemory(eul_stream, 
              eulstreamLength + licenselength + 4
             + PaddingLength(licenselength,sizeof(DWORD)));
   memcpy(eul_stream+0,
          &euIstreamLength,
          4);
   memcpy(eul_stream+4,
          &b64usernamelen,
          4);
   memcpy(eul_stream+8,
          wszbase64ConsumerName,
          b64usernamelen);
   memcpy(eul_stream+8+b64usernamelen+dwordalign,
          &licenselength,
          4);
   memcpy(eul_stream+12+b64usernamelen+dwordalign,
          wszEUL64,
          licenselength);

   // Copy buffer to the stream.
   hResult = pStream->Write(
                (void *)eul_stream,
                eulstreamLength+licenselength+4
                   +PaddingLength(licenselength,
                                  sizeof(DWORD)),
                &bytesWritten);
   CHECK_STG_ERROR("IStream::Write",hResult);

   // Save changes to container file.
   pStorage->Commit(STGC_DEFAULT);

e_Exit:
   // Clean up.
   if (pStorage != NULL)
      pStorage->Release();
   if (pDataSpaceStorage != NULL)
      pDataSpaceStorage->Release();
   if (pTransformInfoStorage != NULL)
      pTransformInfoStorage->Release();
   if (pDRMTransformStorage != NULL)
      pDRMTransformStorage->Release();
   if (pStream != NULL)
      pStream->Release();

   return hResult;
}

See Also

Building a Protected Document Library

Send comments about this topic to Microsoft

Build date: 3/13/2008